## 1. 介紹（Introduction）

歡迎來到 BGT（Blastbay Game Toolkit）語言教學！

這份教學是為**完全沒接觸過 BGT 的初學者**所寫的，不管你對程式語言有沒有基礎，只要你有動力想學習，就非常適合這份教材。

這份教學會從最基本的語法一路教到比較進階的技巧。學完之後，你就可以直接去查閱函式參考文件、研究範例遊戲，甚至開始自己動手做出一款完整的遊戲。

所以，請把腳放上桌，放鬆心情，準備好一起進入 BGT 的世界吧！

---

## 2. BGT 是怎麼運作的？（How does BGT work?）

BGT 主要包含兩個核心組件：

1. 一個是 **執行你的遊戲** 的元件（稱為 *BGT 引擎*）
2. 另一個是 **把你的遊戲變成獨立程式** 的工具（稱為 *BGT 編譯器*）

我們會在下面幾節詳細介紹這兩個部分。不過在那之前，你應該會想問：**「我要怎麼開始做遊戲？」**

---

### 2.1 製作遊戲的流程（The Process of Game Creation）

BGT 引擎原本是一個空白的軟體，它的基本功能包括：

* 播放音效
* 使用計時器
* 讀取/儲存檔案
* 偵測玩家按了哪些鍵

這些功能都是「聽覺導向遊戲」（audiogame）中非常重要的基本元件。

不過 BGT 跟其他「通用語言」（例如 Python 或 C++）最大的不同在於：
BGT 是「讀取你寫的腳本來執行」的。也就是說，你寫的是一種「指令腳本」，告訴 BGT 要做哪些事情，例如：

* 播一段 Logo 聲音
* 檢查有沒有按鍵中斷
* 然後顯示主選單

所有的遊戲邏輯都是用「BGT 特有語法」寫成的腳本。這些語法規則會在後面的章節講解，我們這裡先大致了解它的設計理念就好。

---

### 2.2 BGT 引擎（BGT Engine）

BGT 引擎是整個系統的**核心**。

這個程式會讀取你寫的腳本（也就是你寫的遊戲邏輯），然後根據指令逐步執行出遊戲效果。它的好處是你可以在寫程式的過程中隨時測試，看看有沒有錯誤、哪裡需要改進。

所以如果沒有 BGT 引擎，你寫完遊戲也沒辦法馬上執行來試試看。

---

### 2.3 BGT 編譯器（BGT Compiler）

與引擎「直接執行腳本」不同，**編譯器的功能是把腳本轉換成真正可以獨立運作的 .exe 檔案**。

這個功能很重要，因為：

* 只有你自己會裝 BGT 引擎，一般玩家不會安裝這些開發工具。
* 如果你直接把腳本給別人，他們沒安裝 BGT 是沒辦法執行的。
* 更重要的是：有些腳本裡可能會包含私密資訊（像是登入帳密、伺服器位置），你不想讓別人改動。

透過編譯器，你可以把腳本變成一個單獨的程式，讓玩家只要雙擊 .exe 就能直接玩，不需要知道裡面怎麼寫，也不會暴露你的原始碼。

---

### 📌 補充小筆記：

* **BGT 引擎 = 測試用，方便開發時快速執行腳本**
* **BGT 編譯器 = 發佈用，把腳本變成獨立遊戲程式（exe）**
* 如果腳本裡有密碼、伺服器連線資訊，記得一定要編譯成 exe 再發佈！

---

## 3. 語言語法（Language Syntax）

好了，廢話不多說，我們正式開始寫程式吧！

在開始前，有幾個基礎觀念要先講清楚，這些會讓你之後比較容易理解程式碼是怎麼運作的。

---

### 3.1 指令（Statements）

在程式語言中，「指令」就是告訴電腦該做什麼的一句話。

在 BGT 裡，每一行指令要用 **分號（`;`）結尾**，就像這樣：

```bgt
int score = 0;
```

你可以每行寫一個指令，也可以多行分開寫，不過**分號是必要的**，這樣 BGT 才知道「一句話講完了」。

---

### 3.2 區塊（Blocks）

如果你想讓程式更清楚、更容易閱讀（不管是給自己還是給 BGT 引擎），就會用到所謂的**程式區塊**。

簡單說就是：「把一堆指令包在一起」，這樣當你：

* 想根據某個狀況來做事情（像是音樂有沒有播完？）
* 或者要重複執行某段程式（像是一個迴圈）

這時候就會把相關的指令包成一個「區塊」，告訴 BGT：「這一整塊是要一起處理的喔！」

🧱 區塊就是用 **大括號 `{}` 包起來**，像這樣：

```bgt
if(x > 10)
{
    alert("警告", "x 太大了！");
    x = 0;
}
```

---

### 3.3 表達式（Expressions）

「表達式」其實就是程式裡的某種「條件檢查或動作起點」，大多數都是用來開啟一個區塊的。

一般會包含：

* **關鍵字（keyword）**，像是 `if`、`while`、`do`
* 然後後面接一個 **括號裡的條件或內容**

範例：

```bgt
if(score >= 100)
{
    alert("太棒了！", "你破百了！");
}
```

這邊 `if(score >= 100)` 就是表達式。

⚠️ 注意：表達式**不能加分號 `;`**，因為它不是一個指令，而是一個「判斷條件」。你是在說：「如果這個條件成立，才執行裡面的東西」。

---

### 3.4 註解（Commenting）

**註解**是給「人」看的，不是給程式看的。

你可以在程式中加一些說明，像是：

* 這段程式是做什麼的？
* 為什麼要這樣寫？
* 作者是誰、什麼時候寫的
* 還沒寫好的地方先標記起來以後再改

註解是很好的習慣，不然過了一年自己回頭看程式也會一臉問號 😂

📌 有兩種註解方式：

---

#### 📝 單行註解（Single-line Comment）

用 `//` 開頭，後面那一整行都會被忽略：

```bgt
// 這行是說明分數初始化
int score = 0;
```

即使你寫「我好討厭這個引擎」，BGT 也完全不會理你，因為它根本不會讀進去 😆

---

#### 📝 區塊註解（Block Comment）

如果你要寫一大段說明，就用 `/*` 開始，`*/` 結束：

```bgt
/* 
這是多行註解：
作者：mingo
用途：這段是主選單處理邏輯
記得之後加上背景音樂
*/
```

你甚至可以把一整本小說貼進去（當然不建議），只要電腦還撐得住 😄

---

### 📚 小提醒：

| 類型   | 語法      | 用法               |
| ---- | ------- | ---------------- |
| 單行註解 | `//`    | 在一行尾巴加註解說明       |
| 區塊註解 | `/* */` | 用來註解多行文字或暫時停用程式碼 |

---

這一章的重點就是告訴你：

> BGT 的語法其實很單純，只要了解「語句、區塊、條件、註解」這幾個核心，就能開始寫出簡單的遊戲邏輯！

---

## 4. 在螢幕上顯示文字

學一種新程式語言時，最常做的第一件事就是：

👉 **在螢幕上印出一段文字**

雖然看起來很簡單，但其實這個動作非常重要，它可以幫助你：

* 熟悉語法
* 瞭解程式的運作流程
* 建立對這個語言的基本概念

說了這麼多，我們直接來實作看看！

---

### 🔸 範例程式碼

```bgt
void main()
{
    alert("Hello", "I am a BGT script!");
}
```

---

### ✨ 程式碼解析

讓我們一句一句來看這段程式碼在幹嘛。

---

#### 🧩 `void main()`

這行的意思是：「這是主程式開始的地方！」

* `void` 是說這個函式**不會回傳任何結果**（目前先不用管太多，初學者先記得這樣寫就對了）
* `main()` 是 BGT 運行時會**自動執行的第一個函式**

📌 小提醒：你每次寫一支新的 BGT 腳本時，**一定要有這個 `main()` 函式**，不然遊戲不會開始喔！

---

#### 🧩 `{`

這個是「程式區塊」的開始。

還記得上一章說的嗎？區塊要用 `{` 和 `}` 包起來，代表這一整段程式是屬於 main 函式的內容。

---

#### 🧩 `alert("Hello", "I am a BGT script!");`

這行是我們的主角 🎉

* `alert` 是 BGT 提供的一個內建函式（功能），可以**跳出一個訊息視窗**。
* 裡面有兩個參數：

  * 第一個 `"Hello"` 是**標題**
  * 第二個 `"I am a BGT script!"` 是**訊息內容**
* 每個函式呼叫都要用 `()` 包住參數
* 多個參數之間用逗號 `,` 分隔
* 整句話最後要記得加上分號 `;` 表示結束

📌 **文字要放在雙引號 `"` 裡面**，這樣程式才知道這是要顯示的文字，不是變數或程式語法。

---

#### 🧩 `}`

這代表 `main()` 函式的內容結束了。

---

### 🔍 再看一次完整程式

```bgt
void main()
{
    alert("Hello", "I am a BGT script!");
}
```

這段程式一執行，就會跳出一個視窗，上面寫著：

```
Hello
I am a BGT script!
```

---

### 📘 補充觀念：為什麼這麼重要？

這個簡單的例子幫助你學會了幾個重要觀念：

| 概念        | 說明         |
| --------- | ---------- |
| `main()`  | 程式的起點      |
| `{}`      | 表示區塊       |
| `alert()` | 呼叫內建函式顯示訊息 |
| `"`       | 表示字串文字     |
| `;`       | 指令結束符號     |

---

### ✅ 小挑戰

你可以試試看改寫成這樣：

```bgt
void main()
{
    alert("警告", "這是你第一次寫的 BGT 程式！");
}
```

執行時應該會出現：

```
警告
這是你第一次寫的 BGT 程式！
```

---
## 5. 變數（Variables）

### 5.1 變數是什麼？（Variables; What Are They?）

如果你以前上過數學課，有學過一點點「等式」的觀念，那理解「變數」對你來說應該不會太困難。

但就算你以前上課都在發呆，或像我一樣在教室後面玩「吊死鬼」遊戲也沒關係，這裡我們用一個最簡單的方式來說明什麼是變數。

---

### 🧺 變數就像是一個裝東西的籃子

你可以把「變數」想像成一個籃子，它可以用來裝某個數值或文字。

比方說：

* 你可以用一個變數來記錄「玩家的血量」
* 或是記錄「今天魚的價格」
* 甚至是像《銀河便車指南》裡的「生命的意義」42 😆

總之，變數可以存放任何你想用的數值，而你可以隨時去讀取它、修改它。

---

### BGT 支援的變數型態有 5 種：

1. 整數（integer）👉 只能儲存整數（像 5、-2）
2. 浮點數（floating point）👉 可以儲存小數（像 3.14）
3. 字串（string）👉 儲存文字
4. 布林值（boolean）👉 儲存「真或假」
5. 物件（object）👉 比較進階的類別資料

---

### 5.2 宣告與指定變數（Declaring and assigning variables）

你在使用變數前，**一定要先告訴 BGT：**

1. **你要用哪種型態**（例如：整數、字串）
2. **你要給它取什麼名字**（變數名稱）

變數的命名規則：

* 名稱可以包含英文大小寫、數字、底線（\_）
* 但名字**不能用數字開頭**

---

### ✍️ 範例：

```bgt
string your_name;
```

這一行的意思是：「我想建立一個字串型態的變數，叫做 your\_name。」

你可以想像這個變數會儲存玩家的名字。

📌 別忘了，每個指令後面都要加上分號 `;`！

---

#### ✅ 如果你想一開始就給它一個值：

```bgt
string winning_message = "Congratulations! You have won the game!";
```

這代表：

1. 建立一個字串型態的變數
2. 名字叫做 `winning_message`
3. 它的值是「Congratulations! You have won the game!」

這種方式叫做「宣告＋指定值」一次完成。

---

### ⚠️ 如果你只宣告但沒給值：

```bgt
int x;
```

這樣是合法的，但風險很高。因為 `x` 的值會是記憶體中亂七八糟的內容，**你不知道它是什麼！**

BGT 可能會警告你：「你這個變數還沒給值喔」，但不一定能每次都抓到。所以最安全的做法是：**只要一建立變數，就給它一個預設值。**

---

### 5.3 整數變數與壞掉的水蜜桃（Integral Variables and Bad Peaches）

所謂「整數變數（integral variable）」就是只能儲存「整數」的變數，不支援小數點。

你可以對整數變數做加（+）、減（-）、乘（\*）、除（/）等運算。

---

### 🍎🍌🍊 水果加總範例

```bgt
int apples = 5;
int bananas = 2;
int oranges = 8;
int fruit_basket = apples + bananas + oranges;
```

這裡我們建立了 4 個變數：

* `apples`：有 5 顆蘋果
* `bananas`：2 根香蕉
* `oranges`：8 顆柳丁
* `fruit_basket`：把三種水果加起來的總數

---

### 🍑 進階一點，加上一顆壞掉的水蜜桃：

```bgt
int fruit_basket = apples + bananas + oranges + 1;
```

這行多加了 `+1`，代表又多了一顆壞掉的水蜜桃。

也順便示範一件事：**你可以在一行數學運算裡混合「變數」和「數字常數」來組合算式。**

---

### 🍊 假設我們只放一半的柳丁進籃子裡，會怎樣？

```bgt
int robbed_basket = fruit_basket - (oranges / 2);
```

* 原本是 5 + 2 + 8 + 1 = 16 顆
* 拿掉一半柳丁（8 ÷ 2 = 4）
* 所以 `robbed_basket = 16 - 4 = 12`

👉 括號 `(oranges / 2)` 的作用，是確保數學運算的順序正確！

---

### 🧠 一段比較奇怪但有趣的運算：

```bgt
int x = 3;
x = x * 3;
int y = 8;
int z = x / y;
z += x - 1;
x *= z + 4;
```

這段沒什麼實際用途，只是示範各種數學操作：

* `+=`：等同於 `z = z + (x - 1)`
* `*=`：等同於 `x = x * (z + 4)`

---

### ➗ 模數（Modulus）運算 `%`

模數 `%` 是「除法取餘數」的意思：

```bgt
int x = 11;
x %= 3;  // 等同於 x = x % 3;
```

* 11 ÷ 3 = 商 3、餘 2
* 所以 x 最後是 2

這在做偶數判斷、循環編號時很好用。

---

### ➕➖ 自動加減（++ / --）

這兩個超好用！

```bgt
x++;
```

這等於 `x = x + 1`，而且更快更簡潔。

---

### 🧮 不同大小的整數型態（補充）

有時你會需要控制變數所佔的記憶體大小或值的範圍，以下是幾種常見的整數型態：

| 型態       | 說明                    |
| -------- | --------------------- |
| `int8`   | 1 位元組（-128 到 127）     |
| `uint8`  | 無號，0 到 255            |
| `int16`  | 2 位元組（-32768 到 32767） |
| `uint16` | 無號，0 到 65535          |
| `int32`  | 4 位元組（-21 億到 21 億）    |
| `uint32` | 無號，0 到 42 億多          |

📌 另外還有幾個別名：

* `int` = `int32`
* `short` = `int16`
* `long` = `int32`
* `uint` = `uint32`
* `ushort` = `uint16`
* `ulong` = `uint32`

---

✅ 到這裡，你已經學會了：

* 怎麼建立變數
* 怎麼給它值
* 怎麼做運算
* 怎麼用加減乘除與餘數

---

## 📌 5.4 浮點數變數（Floating point variables）

浮點數變數其實就是「可以包含小數點的數字變數」，就像我們在數學裡學過的那樣。

如果你有學過「分數」或「小數」，你就差不多知道浮點數是什麼了。它們可以是正數也可以是負數。

BGT 支援兩種浮點數型別：

* `float`：單精度浮點數（32 位元），比較省空間，但能表示的數值範圍比較小。
* `double`：雙精度浮點數（64 位元），比較大顆，能處理更大的或更精確的數字，建議預設用這個。

### ✅ 什麼時候用 float？什麼時候用 double？

如果你不確定變數裡會放什麼數字，**建議用 `double`**，因為它比較保險，不容易爆掉。

另外要注意一點：如果你給變數一個超過它容量的數字（例如太大），編譯器會警告你，然後這個變數會被重設成它的最小值。這可能會造成 bug，所以一定要自己控制好變數的數值變化。

---

## 🧵 5.5 字串變數（String Variables）

字串變數就跟我們在聊天、打字時用的文字差不多。你可以用它來記錄玩家的名字、檔案路徑、訊息內容、任何一段文字資料。

### 🧠 簡單記法

字串 = 文字
變數 = 用來存東西的名字

所以「字串變數」就是：「用來存文字資料的變數」。

### 📝 字串一定要用引號括起來

```bgt
string name = "John";
```

這行的意思是：「建立一個叫 `name` 的字串變數，裡面放的是 John 這段文字。」

> 如果你不加引號，BGT 就會以為你是在寫程式指令而不是文字，會出錯。

### 📢 alert() 與字串的搭配

```bgt
string my_name = "John Doe";
alert("My name is", my_name);
```

這行會顯示一個訊息視窗，標題是 `"My name is"`，內容是 `my_name` 的值，也就是 `"John Doe"`。

> ⚠ 如果你寫成 `alert("My name is", "my_name");`，那它就真的會顯示字面上的 `"my_name"` 而不是變數的內容。

---

### ✨ 字串可以串接

你可以用 `+` 來把字串跟其他東西串在一起：

```bgt
string my_name = "John Doe";
int age = 23;
string message = "My name is " + my_name + ", I'm " + age + " years old.";
```

這會組合成這樣的訊息：

```
My name is John Doe, I'm 23 years old.
```

不管是文字（字串）、數字（整數），都可以接起來，只要最終能變成字串。

---

### 🎲 結合隨機數字（random）

```bgt
int age = random(5, 50);
```

這行會讓 `age` 變成 5 到 50 之間的隨機整數。

再搭配字串可以做出：

```bgt
string message = "I'm " + age + " years old.";
```

每次執行都會說不同年齡，很適合做遊戲角色對話等隨機訊息。

---

### 🧪 字串也能 +=

你也可以用 `+=` 來把字串接上新文字：

```bgt
string my_string = "Hello";
my_string += " world!";
```

這樣 `my_string` 就會變成 `"Hello world!"`

但注意：字串不支援 `-`、`*`、`/` 等數學符號，因為字串不能做數學運算。

---

### 🔍 特殊字元要加反斜線 `\`（Escape character）

有些字元不能直接寫在字串裡，比如換行、引號、反斜線等，需要「跳脫符號」處理。

常見的跳脫字元如下：

| 原始寫法 | 實際顯示          |
| ---- | ------------- |
| `\n` | 換行（newline）   |
| `\r` | 回車（Windows 用） |
| `\t` | Tab 縮排        |
| `\"` | 雙引號           |
| `\\` | 反斜線本身         |

例如：

```bgt
string s = "這是第一行。\r\n這是第二行。";
```

這會在訊息中分成兩行顯示。

又例如：

```bgt
string s = "你安裝的位置是 \"C:\\program files\\bgt\\game\"";
```

會顯示：

```
你安裝的位置是 "C:\program files\bgt\game"
```

---

### ✅ 小結重點

* 浮點數用來存小數，建議預設用 `double`。
* 字串是用來存文字的變數，要用雙引號 `"` 包起來。
* 字串可以用 `+` 或 `+=` 串接。
* 可以把數字變數放進字串中。
* 特殊字元要用 `\` 跳脫，例如 `\n` 換行、`\"` 顯示雙引號。

---

## 🔹5.6 常數（Constants）

### ✅ 什麼是常數？

常數（constant）跟變數（variable）很像，不同的地方在於：

> 「常數的值一旦設定，就**不能再改**了。」

也就是說，在程式運作期間，常數的值是**固定不變**的；而變數可以隨時更換內容。

這也是為什麼它叫做「常數」──意思是它的值「一直都一樣」。

---

### ✅ 常數的好處

使用常數有兩個主要目的：

1. **增加程式的可讀性**（好懂、清楚）
2. **方便修改與維護**

---

### ✅ 常數的宣告方式

和變數差不多，只是要加上一個關鍵字 `const`：

```bgt
const string snd_ext = ".wav";
```

這樣就定義了一個名為 `snd_ext` 的**字串常數**，值是 `.wav`，不能再被修改。

---

### 🔸 範例：套用常數來管理音效副檔名

```bgt
const string snd_ext = ".wav";
sound gun;
sound beep;
sound ambience;
sound music;

gun.load("sounds/gun" + snd_ext);
beep.load("sounds/beep" + snd_ext);
ambience.stream("sounds/wind" + snd_ext);
music.stream("sounds/music" + snd_ext);
```

📌 **說明：**

* `snd_ext` 是 `.wav`
* 每個音效都用 `"檔名" + snd_ext` 來載入
* 以後如果我們改用 `.ogg` 格式，只需要改：

```bgt
const string snd_ext = ".ogg";
```

✅ 一行就搞定，不用去改每一個檔案路徑，非常方便！

---

### 🔸 BGT 裡也有內建常數

很多 BGT 函式的參數也可以使用內建的常數。舉例：

```bgt
file.open("save.txt", file_write);
```

`file_write` 就是個內建常數，實際上代表一個數字（例如 2），只是我們用有意義的名字來代表，讓程式看起來更清楚。

📌 如果你寫 `file.open("save.txt", 2);` 雖然也會動，但不如寫 `file_write` 來得清楚。

---

## 🔹進階：列舉常數 enum（enumeration）

BGT 還支援一種**特殊的常數群組**，叫做 `enum`，全名是「enumeration（列舉）」。

### ✅ enum 是什麼？

* 是一組**整數型的常數**
* 用來將多個相關的常數整理在一起
* 定義在程式**最外層（全域）**

---

### 🔸 範例 1：定義移動方向

```bgt
enum movement {
    left = -1,
    right = 1
}
```

* `movement` 是一組列舉常數
* `left` 的值是 -1，`right` 是 1
* 之後可以這樣用：

```bgt
int direction = movement.left;
```

---

### 🔸 範例 2：定義武器種類

```bgt
enum weapon {
    fist,
    club,
    slingshot,
    gun,
    bomb
}
```

這裡**沒寫值也可以**，BGT 會自動從 0 開始依序編號：

* `fist = 0`
* `club = 1`
* `slingshot = 2`
* `gun = 3`
* `bomb = 4`

📌 這樣做的好處是：你專心設計內容就好，不用手動對號碼。

---

### 🚨 注意！

`enum` 只能在「全域」範圍定義，**不能寫在函式裡面**！

---

## 🧠 小小總結：

| 類型                              | 可變？    | 範例              | 說明   |
| ------------------------------- | ------ | --------------- | ---- |
| `int x=5;`                      | ✅ 可以改  | `x=10;`         | 普通變數 |
| `const int x=5;`                | ❌ 不能改  | `x=10;` ➜ 錯誤    | 常數   |
| `enum color {red, green, blue}` | ❌ 組合常數 | `color.red` ➜ 0 | 列舉   |

---

## 🧾 5.7 章節總結：變數與常數基礎觀念

這一章講的是「變數與常數」，是程式設計最基本、最重要的核心觀念之一。以下是快速重點整理：

---

### ✅ 1. 變數是像「籃子」一樣的東西

* 你可以把資料放進變數（這個籃子）裡面。
* 每個變數可以放的東西類型（數字、文字等）不太一樣。

🔸 **比喻：**

> 如果你家有一個水果籃只能放蘋果，那你就不能放西瓜。同樣，`int` 只能放整數，`string` 只能放文字。

---

### ✅ 2. 常數就是「不能改變的變數」

* 一旦你設定好常數的值，就不能再改了。
* 適合放一些不會變的設定，比如副檔名、最大生命值等等。

---

### ✅ 3. 整數變數（int）

* 可以放**正數或負數**，也可以選擇只放正數（unsigned）。
* 但不可以有小數點。

---

### ✅ 4. 浮點數變數（float, double）

* 可以放**小數點**的數字。
* 可以是正數或負數。
* 若你還不確定要放什麼數字，用 `double` 比較安全。

🔸 **補充：**

> `double` 通常比 `float` 精確，可以處理更大的數字或更多小數位。

---

### ✅ 5. 可以對數字變數做數學運算

```bgt
int a = 3;
int b = 5;
int c = a + b;  // 結果是 8
```

* 你可以用變數或直接用數字來算。

---

### ✅ 6. 請記得追蹤你的變數使用狀況

* 如果你放進去超過能容納的數字（例如 int 最大值），可能會爆炸（叫做 overflow）。
* 結果會不正常。

---

### ✅ 7. 字串變數（string）是字元組成的資料

* 例如：`"Hello"`、`"John Doe"` 都是字串。
* 字串可以組合起來，像這樣：

```bgt
string s = "My name is " + name + "!";
```

---

### ✅ 8. 數字加法 vs 字串加法

```bgt
int a = 1;
int b = 1;
int c = a + b;  // 結果是 2

string sa = "1";
string sb = "1";
string sc = sa + sb;  // 結果是 "11"，因為是字串合併
```

🔸 **提醒：**

> 雖然「1+1」看起來都是一樣的，型別不同，結果也會完全不同！

---

### ✅ 9. 變數與常數是寫程式、做遊戲的基礎

* 不管寫哪種程式、做哪種遊戲，變數和常數都一定會用到。
* 沒有它們，你沒辦法記住玩家的分數、生命、名字、進度...

---

### ✅ 10. 大小寫有差！（區分大小寫）

* 在 BGT 裡面，變數跟常數名稱會區分大小寫。

```bgt
int Score = 10;
int score = 20;
```

🔸 這兩個其實是**不同的變數**，你必須用跟宣告時一樣的大小寫來呼叫它們。

---

## 🧠 總結：你現在該知道的是…

| 概念           | 說明                     |
| ------------ | ---------------------- |
| 變數           | 可以改變的資料容器（像籃子）         |
| 常數           | 無法改變的變數（固定的設定）         |
| int          | 整數                     |
| float/double | 有小數點的數值                |
| string       | 一串文字，例如名字、路徑、對話        |
| 運算           | 數字可以加減乘除，字串可以用 + 合併    |
| 大小寫          | `Score` ≠ `score`，務必注意 |

---
## 🧪 初階題（理解基本概念）

### ✅ 題目 1：整數變數的宣告與相加

請宣告兩個整數變數 `a` 和 `b`，分別設定為 5 和 7，然後把它們相加起來，並用 `alert` 顯示結果。

📌 提示：用 `int` 宣告變數，用 `+` 做加法。

---

### ✅ 題目 2：字串變數的組合

請宣告兩個字串變數 `first_name` 和 `last_name`，分別是 `"John"` 和 `"Doe"`，然後組合成一句話：「Your name is John Doe」，用 `alert` 顯示出來。

📌 提示：字串相加要用 `+`，並記得加空格。

---

### ✅ 題目 3：變數與常數的差別

請建立一個常數 `const string ext=".mp3";`，並宣告一個音樂變數 `music`，然後使用 `music.stream("bgm"+ext);` 播放 `bgm.mp3` 檔案。

📌 提示：常數用 `const` 宣告，變數用一般方式。

---

## 🧪 中階題（開始混合型別）

### 🔶 題目 4：混合文字與數字

請宣告一個 `string name="Alice"` 和一個 `int age=30`，組合成一句：「Alice is 30 years old.」並顯示。

📌 提示：將數字轉為字串是自動的，只要用 `+`。

---

### 🔶 題目 5：使用 += 來組合字串

宣告一個字串 `msg="Welcome"`，然後用 `+=` 加上 `" to the game!"`，最後顯示結果。

📌 提示：`msg += " 新的內容";` 是有效的語法。

---

### 🔶 題目 6：使用亂數來設定變數

請宣告一個名字變數 `string hero="勇者小明"`，然後使用亂數 `random(10, 50)` 來表示他的等級，最後顯示一句：「勇者小明的等級是 X！」

📌 提示：`int level = random(10, 50);`。

---

## 🧪 進階題（條件與組合思維）

### 🔷 題目 7：多種武器設定

請建立一個 enum 叫做 `weapon`，裡面有 `sword`, `axe`, `bow`, `magic`，並宣告一個變數 `weapon my_weapon = weapon.magic;`，最後顯示你選了哪種武器。

📌 提示：用 `enum` 建立型別，要在全域宣告。

---

### 🔷 題目 8：建立常數副檔名，切換格式

請設計一個常數 `ext=".wav"`，使用這個常數組合成 `bgm.wav`、`menu.wav`、`gameover.wav` 等三個檔案的完整路徑，並用 `alert` 顯示出來。

📌 提示：當你要改副檔名時，只要改常數內容即可。

---

### 🔷 題目 9：多變數組合輸出

請建立以下變數：

* `string player_name="小明"`
* `int hp=100`
* `int mp=30`
* `int level=12`

請組合成一句：「玩家小明（等級 12）目前 HP: 100, MP: 30」並顯示出來。

📌 提示：多個變數可用 `+` 一起串起來。

---
## 6. function

###  6-1 ：函式是什麼？為什麼需要？

#### 一、什麼是「函式（Function）」？

在程式語言裡，「函式」就是一段**有名字的程式碼區塊**。你可以把它想像成一個工具箱裡的工具──你給它一個名字，以後只要叫這個名字，它就會幫你自動執行裡面的內容。

##### 🎮 在 BGT 的遊戲開發裡：

* 如果你寫了一段「播放攻擊音效」的程式碼，就可以把這段包成一個 `play_attack_sound()` 的函式。
* 之後只要你想讓角色攻擊時播放聲音，就直接呼叫 `play_attack_sound()`，很方便、很清楚。

---

#### 二、為什麼要使用函式？

##### ✅ 好處一：讓程式更有條理

如果你把整個遊戲的邏輯都寫在一大段程式碼裡，很容易亂、很難修改。
用函式可以**把功能切開整理好**，就像整理好的資料夾，誰看都一目了然。

> 比喻：想像你要做一頓大餐，你會把炒菜、煮湯、洗碗分開做。程式也一樣，要把每個步驟變成一個獨立的函式。

##### ✅ 好處二：可以重複使用，不用一直複製貼上

如果你有一段程式碼會在很多地方用到，那就寫成函式，**需要時只要叫一下就好**，不必複製來複製去。

> 範例：你寫了 `play_jump_sound()`，以後角色 A、角色 B、甚至敵人跳起來時都可以共用這段聲音邏輯。

---

#### 三、BGT 內建的函式例子

其實你早就用過函式了，例如：

```bgt
alert("標題", "內容");
```

這就是一個叫 `alert` 的內建函式，它會在畫面上跳出一個訊息視窗。

這些函式都幫你封裝好了功能，你只要傳進參數（像文字），它就幫你完成事情，這就是函式的基本精神。

---

#### 四、自訂函式 vs 內建函式

* **內建函式**：像 `alert()`、`random()`, `play()`，是 BGT 已經幫你寫好的。
* **自訂函式**：你可以自己寫一段叫 `jump()`、`enemy_die()` 的函式，讓遊戲角色依你的規則動作。

---

#### ✅ 本節練習題（選擇題）

1. 下列哪一個不是使用函式的好處？
   A. 讓程式看起來更整齊
   B. 讓每一行程式都不重複
   C. 可以重複使用程式碼
   D. 分類不同的功能

> 正確答案：B（函式不能保證每一行程式都不重複）

---

### 🧩 第 6-2 節：主函式 `main()` 與基本語法結構

#### 一、什麼是 `main()`？

在 BGT 裡，每個程式都**必須**有一個名為 `main()` 的函式，這是整個程式的「入口點」或「起跑線」。

你可以把 `main()` 想像成：

* 🕹️ 遊戲的「開始畫面」
* 📂 檔案的「封面頁」
* 🎬 電影的「開場畫面」

沒有這個 `main()`，程式就不知道從哪裡開始執行，也就無法運作。

---

#### 二、最簡單的範例

```bgt
void main() {
    alert("Test", "We are now using the main function.");
}
```

##### 🧱 這段程式碼代表：

* `void`：這個函式**不會回傳任何資料**。
* `main`：函式名稱，必須這樣命名。
* `()`：括號裡是**參數列**（這裡是空的）。
* `{}`：大括號中是這個函式的**內容區塊**。
* `alert(...)`：這是內建函式，用來顯示訊息。

> 💡 小提醒：所有程式都會從這個 `main()` 函式開始跑，其他函式要等被呼叫才會執行。

---

#### 三、語法結構說明

BGT 的函式結構有幾個基本元素：

| 元素    | 說明                                     |
| ----- | -------------------------------------- |
| 回傳型別  | 像 `void`、`int`、`string`，代表函式會回傳什麼類型的資料 |
| 函式名稱  | 自己取的名字，像 `main`、`play_sound`、`jump`    |
| 參數列表  | 寫在括號內，可以放入輸入資料；沒有參數也可以空著               |
| 大括號區塊 | 包住這個函式的程式內容                            |

---

#### 四、回傳值與 `void` 是什麼？

* 如果一個函式不需要回傳資料，就寫 `void`。
* 如果你想讓函式**回傳一個數字或文字**，就改成 `int` 或 `string` 等型別。

> 🔁 我們下一節會講更進階的函式：怎麼回傳資料、怎麼傳入參數。

---

#### ✅ 本節練習題

1. 如果你沒有寫 `main()` 函式，會發生什麼事？
   A. 程式自動新增一個空的 main
   B. 程式可以跑但會跳過 main
   C. 程式會出錯，無法執行
   D. 程式從第一行開始執行

> 正確答案：C

2. 下列哪一個是正確的函式定義？
   A. `function main { alert("hi"); }`
   B. `void main() { alert("hi"); }`
   C. `main void() { alert("hi"); }`
   D. `main { alert("hi"); }`

> 正確答案：B

---
### 🎯 第 6-3 節：函式的參數與回傳值

在這一節，我們會正式開始撰寫屬於你自己的函式，並學會怎麼：

1. 給函式「輸入資料」（稱為參數）
2. 從函式中「拿回資料」（稱為回傳值）

---

#### 🧪 函式參數的基本概念

想像你有一台果汁機（函式），它需要兩樣東西才能工作：一顆蘋果和一顆香蕉（參數）。你放進去，它幫你打成果汁（回傳值）。

程式裡也是一樣，我們可以設計一個函式來處理兩個數字相加的動作：

```bgt
int add_numbers(int first, int second) {
    int result = first + second;
    return result;
}
```

* `int add_numbers(...)`：這個函式會**回傳整數**
* `first`、`second` 是輸入的**參數**
* `return result`：回傳計算的結果

---

#### 🧪 在主程式裡使用這個函式

```bgt
void main() {
    int x = add_numbers(3, 5);
    alert("Result", "3 + 5 is... " + x + "!");
}
```

* 我們呼叫 `add_numbers(3, 5)` 把結果存進變數 `x`
* 然後用 `alert` 顯示出來

---

#### 🧩 專業補充：你也可以這樣寫

你不一定要多用一個變數來接結果，可以**直接在函式裡呼叫函式**：

```bgt
alert("Result", "3 + 5 is... " + add_numbers(3, 5) + "!");
```

這樣會更簡潔，尤其在不需要重複使用結果時非常實用。

---

#### 🎀 回傳值不一定是數字，也可以是文字（字串）

範例：

```bgt
string string_magic() {
    return "wow";
}
```

然後你可以這樣用：

```bgt
alert("Magic", string_magic() + string_magic() + string_magic());
```

會輸出：`wowwowwow`

---

#### ⚠️ 注意：每個函式一次只能 `return` 一個東西！

```bgt
return 3;
return 5;  // ❌ 這行永遠不會執行到
```

---

#### 🎯 小重點整理

| 概念             | 說明                |
| -------------- | ----------------- |
| `參數`           | 放在括號內，讓你可以傳資料進來   |
| `回傳值`          | 用 `return` 回傳結果出去 |
| `int`、`string` | 決定函式會回傳的資料型態      |
| `void`         | 表示這個函式不會回傳任何東西    |

---

#### 🧠 實務建議（BGT 遊戲開發觀點）

* **小功能用函式包起來**，像：加法、轉換文字、判斷條件等
* **主程式避免塞滿太多邏輯**，拆成小函式可讀性更高
* **命名要清楚**：像 `add_numbers`、`get_score`、`play_intro_music` 這樣能讓人一看就懂用途

---

#### ✅ 本節小練習

1. 下列哪一個函式會回傳字串？
   A. `void get_name()`
   B. `int get_name()`
   C. `string get_name()`
   D. `return get_name()`

> 正解：C

2. 若你有這樣的函式：

   ```bgt
   int double_up(int x) {
       return x * 2;
   }
   ```

   下列哪個用法是正確的？
   A. `int y = double_up();`
   B. `double_up(5);`
   C. `int y = double_up(5);`
   D. `return double_up(5);`

> 正解：C

---
### 🧠 第 6-4 節：區域變數與全域變數

在寫程式時，你會使用「變數」來存資料。但這些變數**不是全部都能在整個程式裡通用**，有些變數只能在某個地方用。

這就是今天的主題：**區域變數（Local Variable）** 和 **全域變數（Global Variable）**

---

#### 🌍 全域變數（Global）

如果你在「函式外面」宣告一個變數，那它就是**全域變數**，整個程式都能看得到它、使用它。

```bgt
string my_name = "John Doe";  // 全域變數

void main() {
    alert("Name", my_name); // 可以直接使用
}
```

你不管在哪個函式裡，都可以用 `my_name`，甚至改它的內容。

---

#### 🏠 區域變數（Local）

如果你在「函式裡面」宣告變數，那它就是**區域變數**，只能在那個函式裡使用。

```bgt
void my_function() {
    int number_of_pets = 3; // 區域變數
}
```

如果你在函式外面或其他函式想用 `number_of_pets`，會出錯！

---

#### 🧪 範例說明

```bgt
string my_name = "John Doe";  // 全域

void main() {
    my_function();
}

void my_function() {
    int number_of_hands = 2;  // 區域
    my_name = "Rodney";       // 可以改全域變數
}
```

* `number_of_hands` 只能在 `my_function` 裡使用
* `my_name` 是全域的，在 `main` 和 `my_function` 都能看到

---

#### 💥 為什麼區域與全域要分開？

1. **避免變數名稱衝突**：不同函式裡可以有同樣名字的變數，彼此互不干擾
2. **讓記憶體用得更省**：區域變數只在函式執行時才存在，用完會自動清掉
3. **增加可讀性**：你知道變數在哪裡會被用到，不會搞混

---

#### 🧠 專業補充：BGT 的記憶體管理觀點

* BGT 雖然會自動處理大多數記憶體釋放問題，但你仍要養成**清楚使用範圍的習慣**
* 全域變數太多會造成**難以除錯**、**無法多人協作開發**
* 開發大型遊戲建議將資料集中寫入結構（struct）或類別物件中，再由全域統一管理

---

#### 📋 小重點整理

| 概念     | 說明              |
| ------ | --------------- |
| 區域變數   | 只在某個函式裡面有效      |
| 全域變數   | 整個程式中都能看到與使用    |
| 記憶體使用  | 區域變數用完會釋放，全域不會  |
| 命名衝突處理 | 區域變數優先，全域會被「遮蔽」 |

---

#### ✅ 小測驗

1. 如果你這樣寫：

   ```bgt
   int score = 100;

   void show_score() {
       int score = 0;
       alert("Score", "" + score);
   }
   ```

   結果畫面會顯示什麼？
   A. 100
   B. 0
   C. 錯誤
   D. 沒東西顯示

> 正解：B（區域變數遮蔽全域變數）

2. 哪一個是全域變數的正確用途？
   A. 存遊戲的總分
   B. 計算函式內迴圈次數
   C. 暫時儲存使用者輸入值
   D. 存放每一幀的動畫數值

> 正解：A（因為總分是全局性的資訊）

---

### 🎓 小提醒

全域變數用得好，程式清楚明瞭；用得爛，程式就會變成一坨亂碼。小專案可以偷懶用多一點全域變數，大型專案務必好好規劃。

---
### 🔁 第 6-5 節：一次回傳多個值？用「傳參考」就對了！

在一般情況下，BGT 的函式**只能回傳一個值**，像這樣：

```bgt
int add(int a, int b) {
    return a + b;
}
```

只能回傳「a + b」的結果。如果你想**同時傳回兩個、三個值**，該怎麼辦？

這時就要用到一個超實用的技巧：「**傳參考（pass by reference）**」！

---

#### 🔧 傳參考是什麼？

一般變數傳進函式，是把「值」丟進去，不會改到外面的變數，我們叫做「傳值」。

如果你希望函式可以**直接修改傳進去的變數內容**，就要用「傳參考」，這樣**改變參數就等於改到外面的變數！**

---

#### ✍️ 語法重點：`&out`

```bgt
void my_function(int &out a, int &out b) {
    a = 10;
    b = 20;
}
```

加上 `&out` 的意思是：**這個參數是「傳參考」的，允許函式內部改變它的值。**

---

#### 🎮 實戰範例

```bgt
void main() {
    int x = 1;
    int y = 2;

    my_function(x, y); // 呼叫函式後 x 和 y 會被改變

    alert("結果", "x = " + x + ", y = " + y);  // 顯示 x = 10, y = 25
}

void my_function(int &out first, int &out second) {
    first = 10;
    second = 25;
}
```

* 原本 x 是 1、y 是 2
* 呼叫 `my_function()` 之後，**x 和 y 都被改掉了！**

---

#### 🧠 為什麼這樣做很重要？

因為這樣你就可以：

* 一次修改多個變數
* 不需要用 return 一個個慢慢傳回來
* 資料的來源與去向一目瞭然

---

#### 📘 專業補充：傳參考 vs 傳值

| 種類  | 寫法          | 是否會改到外面變數 | 用途           |
| --- | ----------- | --------- | ------------ |
| 傳值  | int a       | ❌ 不會      | 一般數值傳入函式處理   |
| 傳參考 | int \&out a | ✅ 會       | 想修改外部變數內容時必用 |

---

#### ❓預設是傳值嗎？

是的！在 BGT 裡面，如果你不特別寫 `&out`，那就是「傳值」模式（有時也叫 `&in`），代表函式內部的改動不會影響原本的變數。

---

#### ⛔ 注意事項

1. `&out` 只能用在基本類型（int, string 等）
2. 若變數名稱一樣，請確保不會誤用，否則會產生預期外的改動
3. 不建議用來修改太多全域變數，會讓程式邏輯難以追蹤

---

#### 📋 小練習

請觀察這段程式碼的執行結果：

```bgt
void main() {
    int a = 5;
    int b = 7;
    calculate(a, b);
    alert("結果", "a = " + a + ", b = " + b);
}

void calculate(int &out x, int &out y) {
    x += 3;
    y *= 2;
}
```

**結果會是？**
A. a = 5, b = 7
B. a = 8, b = 14
C. a = 3, b = 2
D. 程式會錯誤

> ✅ 正解：B（因為 `x += 3` 等於 a = 5+3，`y *= 2` 等於 b = 7\*2）

---

#### 🎯 小結論

* 傳參考是「讓函式改外面變數」的方式
* 可以用來**回傳多個結果**，不用 return 好幾個值
* 寫多一點 `&out`，少寫一些重複的 return，會讓程式更簡潔

---

### 🔀 第 6-6 節：函式多載（Function Overloading）

你有沒有想過：
如果我想寫兩個功能差不多的函式，名字可不可以一樣？
答案是：**可以！**

這種技巧叫做 **「函式多載」**（Function Overloading）。

---

#### 🧠 什麼是函式多載？

**多載**的意思就是：

> 「你可以有多個同名的函式，只要它們的參數不同，BGT 會自己選對的來用！」

簡單來說，就是你可以這樣做：

```bgt
int add(int a, int b) {
    return a + b;
}

float add(float a, float b) {
    return a + b;
}
```

上面這兩個函式名字都叫 `add`，但一個處理整數、一個處理浮點數，
**當你呼叫 `add(3, 4)` 時，BGT 會自己挑選適合的版本來執行！**

---

#### 🎮 實戰範例（字串版本也能多載）

```bgt
string my_function(string your_name, int number) {
    return "Hello " + your_name + "! " + number + " people are waiting for you.";
}

int my_function(int a, int b) {
    return a + b;
}

void main() {
    alert("結果", my_function("Daniel", 5)); // 會用字串版本
    alert("數字", "" + my_function(2, 3));   // 會用整數版本
}
```

你會看到：

* 第一個 `alert` 使用了 **字串 + 整數** 版本
* 第二個 `alert` 使用了 **整數 + 整數** 版本

---

#### 🚨 多載的規則

BGT 會根據「**參數的數量與型別**」自動選出正確的函式版本。

你可以改參數的：

* 數量（2 個參數 vs 3 個參數）
* 型別（int vs string）

只要符合下面的規則，多載就是合法的。

---

#### ✅ 合法的多載

```bgt
int fun(int a) { return a; }
int fun(int a, int b) { return a + b; }
string fun(string s) { return s + "!"; }
```

* 名字都叫 `fun`
* 但參數數量與型別都不一樣

BGT 就知道該用哪個！

---

#### ❌ 不合法的多載（會錯）

```bgt
int fun(int a) { return a; }
float fun(int a) { return a + 1.0; } // ❌ 參數一樣，只差回傳型別，不行！
```

在 BGT 裡，「只改回傳型別」不算合法的多載。

---

#### 🎓 專業觀念補充：為什麼要多載？

1. **讓 API 更簡單好記**：你不用背一堆不同函式名
2. **同一個功能，處理不同的資料型別**
3. **保持邏輯一致、程式碼乾淨**

在遊戲中常見用途像是：

* 傳進角色名字時顯示歡迎訊息
* 傳進數字時計算戰鬥傷害
* 傳進座標時計算距離等等…

---

#### 📋 小練習

請問以下程式會執行哪一個 `say` 函式？

```bgt
void say(string s) {
    alert("文字", "你說了：" + s);
}

void say(int number) {
    alert("數字", "你說的數字是：" + number);
}

void main() {
    say("hello");
}
```

✅ 答案：會執行 `say(string s)` 版本，因為參數是字串。

---

#### 🧠 額外觀念延伸（針對進階玩家）

如果你遇到 **兩個函式的參數剛好都可以匹配呼叫時的參數型別（例如 int 可以轉 float）**，BGT 會挑選最接近的那個版本執行。
這種情況稱為「最佳匹配」。

---

#### 🧾 小結論

* 同名不同參數的函式叫做「多載」
* 幫助你統一介面、讓邏輯更清楚
* 參數不同才能算合法的多載（回傳型別不同不行）
* BGT 會自動判斷呼叫哪一個函式版本

---

### 🧩 第 6-7 節：預設參數 Default Parameters

有時候，我們寫函式時會希望某些參數「可有可無」，
如果使用者沒有給，我們就用「預設值」。

這個功能在 BGT 也可以做到，這就叫做 **預設參數**！

---

#### 🧠 什麼是預設參數？

預設參數就是：

> 「在函式宣告時，先幫某些參數設定好預設值。以後呼叫這個函式時，可以選擇要不要給這些參數。」

---

#### 🧪 範例

```bgt
void main() {
    print_info("Hi there!", 10, 20, 30);
    print_info("Hello again!", 99);  // 少給兩個參數沒關係
}

void print_info(string title, int v1=0, int v2=0, int v3=0) {
    alert(title, "V1=" + v1 + ", V2=" + v2 + ", V3=" + v3);
}
```

🔍 分析：

* 第一行：全部都給了，所以會顯示 10, 20, 30
* 第二行：只給一個，v2 和 v3 就使用預設值 0

---

#### 📏 語法規則（一定要記住！）

1. 預設值只能設定在**函式宣告**的地方
2. 有預設值的參數必須排在「最後」

   * ❌ 不可以這樣：

     ```bgt
     void test(int x=0, int y) { }  // 錯誤
     ```
   * ✅ 正確寫法：

     ```bgt
     void test(int y, int x=0) { }  // 正確
     ```

---

#### 🎮 預設參數的遊戲實用情境

預設參數在做遊戲時非常常用，例如：

* 音效播放函式，預設音量為 100：

  ```bgt
  void play_sound(string file, int volume=100)
  ```

* 建立角色時預設血量為 100、魔力為 50：

  ```bgt
  void create_player(string name, int hp=100, int mp=50)
  ```

* 顯示訊息時預設標題為 "訊息"：

  ```bgt
  void show_message(string content, string title="訊息")
  ```

---

#### 🧠 小技巧：與多載搭配使用

有時你也可以用「函式多載」加上「預設參數」設計出很靈活的 API：

```bgt
void show_alert(string title, string text="沒有內容") {
    alert(title, text);
}
```

呼叫時：

```bgt
show_alert("警告");               // 只有標題
show_alert("警告", "請注意！");   // 標題 + 內容
```

---

#### 🧾 小結論

* 預設參數可以讓函式變得「更方便」、「更有彈性」
* 不需要每次都提供全部參數
* 預設參數一定要寫在最後
* 非常適合用在音效、角色建立、顯示訊息等常見用途

---

### 🎓 第 6-8 節：總結與實戰練習

經過這一章，我們從零開始學會了函式的所有基本用法。
無論你是第一次接觸 BGT 或是學過其他語言，這些觀念都是寫出好遊戲的基礎。

---

#### ✅ 你應該掌握的函式重點：

1. **函式是什麼？**
   就是一段有名字的程式碼，可以重複呼叫使用。

2. **void 表示「不回傳任何東西」**
   回傳的東西叫「return 值」，可以是數字、字串、布林等。

3. **函式有「參數」可以傳進資料**
   像 `jump(5)` 就是把 5 傳進 `jump()` 這個函式裡。

4. **main() 是程式的入口點，一定要寫！**

5. **全域變數與區域變數要分清楚**

   * 全域變數：寫在函式外面，全程有效
   * 區域變數：寫在函式裡，只能在那裡用

6. **傳值 vs 傳參考**

   * `&in`（預設）：傳的是值，改不到原本的變數
   * `&out`：可以改外面的變數值（有點像把變數本體傳進去）

7. **函式可以多載（overload）**
   只要參數數量或類型不同，就可以用同一個函式名稱。

8. **預設參數（default values）可以讓函式更靈活**
   少傳幾個參數也不會報錯，會用你指定的預設值。

---

### 🧪 實戰練習題（從簡單到進階）

---

#### 🔹 練習題 1：寫一個函式 `greet()`，會顯示「Hello!」

```bgt
// 題目範例
greet();  // 印出 Hello!
```

---

#### 🔹 練習題 2：寫一個函式 `add(a, b)`，回傳兩數相加的結果。

```bgt
int total = add(3, 7);  // 應該得到 10
```

---

#### 🔹 練習題 3：寫一個函式 `say_hello(name)`，印出「Hello, name!」

```bgt
say_hello("Alex");  // 印出 Hello, Alex!
```

---

#### 🔹 練習題 4：用傳參考方式，讓函式幫你計算平方與立方

```bgt
int square, cube;
calculate(4, square, cube);
// square = 16, cube = 64
```

---

#### 🔹 練習題 5：寫一個函式可以顯示玩家資訊，有預設參數

```bgt
show_info("Alice");  // 血量顯示為預設 100
show_info("Bob", 80);  // 血量為 80
```

---

#### 🔹 挑戰題：寫一個函式 `play_sound(filename, volume=100)`

可以播放音效，volume 是預設值（不用真的播放，模擬 alert 就好）

---

## 📚 結語：為什麼函式這麼重要？

> 因為好的函式設計，可以讓你的遊戲更清楚、好維護、效率更高。

在未來的章節中，我們會進一步學習類別、陣列、物件導向等進階主題，
但「函式」永遠是你的好幫手。

---
## 7. 條件

---

### 📘 7.1.1 如果條件（If statements）是什麼？

「if 條件語句」的邏輯就像我們平常講話那樣，例如：

> 如果我感冒了，就幫我跟爸爸說。

電腦程式也可以做出這樣的判斷，只不過是根據資料（變數的數值）來做決定。例如你可以這樣寫：

```bgt
if(health < 21)
{
  // 播放心跳聲音
}
```

📝 **備註說明：**
這裡的意思是：「如果變數 `health`（代表血量）小於 21，就執行大括號 `{}` 裡的內容」。也就是血太少了，就讓心跳加快，營造緊張氣氛。

---

### 📘 7.1.2 if…else 條件語句的進一步應用

如果想根據不同情況做出不同反應，你可以加上 `else`：

```bgt
if(health < 21)
{
  // 播放心跳聲音
}
else
{
  // 做其他事情，例如顯示血量正常
}
```

📝 **備註說明：**
這代表有「兩種可能」，程式會檢查 `health < 21` 是否成立：

* 成立（血少）→ 播心跳聲。
* 不成立（血夠）→ 執行 else 裡的動作。

---

### 📘 7.1.3 括號什麼時候要寫？可以省略嗎？

當 if 條件裡 **只有一行動作**，可以省略大括號：

```bgt
if(health < 21)
// 播心跳聲
```

但如果有**多個動作**，一定要加括號：

```bgt
if(health < 21)
{
  // 播心跳聲
  alert("警告", "你快掛了！");
}
```

✅ **建議：不管幾行，最好都加上大括號 {}，寫起來比較安全、好維護。**

---

### 📘 7.1.4 if 裡也可以有變數？

是的，但要注意範圍！在 if 裡面宣告的變數，**只在那個 if 的大括號裡有用**。

例如：

```bgt
if(score > 100)
{
  int bonus = 50;
}
```

⚠️ 離開 if 區塊後，`bonus` 就不存在了。

---

### 📘 7.1.5 各種判斷條件的語法

| 判斷語法     | 意義                | 限制      |
| -------- | ----------------- | ------- |
| `x == y` | x 等於 y            | 任何型別都可用 |
| `x != y` | x 不等於 y           | 任何型別都可用 |
| `x < y`  | x 小於 y            | 只能數字    |
| `x <= y` | x 小於等於 y          | 只能數字    |
| `x > y`  | x 大於 y            | 只能數字    |
| `x >= y` | x 大於等於 y          | 只能數字    |
| `!x`     | x 為 false 時為 true | 只能布林變數  |

---

### 📘 7.1.6 = 和 == 有什麼不一樣？

很多新手會寫錯：

```bgt
if(x = y) // ❌ 錯誤：這是把 y 的值賦值給 x，不是比較
```

正確的比較要用 `==`：

```bgt
if(x == y) // ✅ 正確：檢查 x 是否等於 y
```

---

### 📘 7.1.7 完整的例子說明

以下是一段完整的範例：

```bgt
string my_name="John Doe";
int age=random(5, 50);
string message_string="My name is " + my_name + ", I'm " + age + " years old which means that I am ";

if(age<18)
{
  message_string+="a minor!";
}
else
{
  message_string+="of full age!";
}

alert("Important information", message_string);
```

💡 **說明：**

* 隨機生成一個年齡。
* 判斷是否未滿 18 歲。
* 組成一段句子，最後跳出訊息框。

---

### 📘 7.1.8 巢狀 if（if 中再 if）

if 裡面也可以放 if，這叫做「巢狀條件判斷」。

🔽 例如：

```bgt
if(key_pressed(KEY_F4))
{
  if(key_down(KEY_LMENU))
  {
    alert("Fine!", "如果你真的想退出程式，那就掰掰吧。");
    exit();
  }
  else
  {
    alert("Um...", "你是不是忘了按住 Alt？");
  }
}
```

📝 **備註說明：**

* 先檢查使用者有沒有按下 F4。
* 如果有，再檢查是否同時按住左邊的 Alt 鍵（KEY\_LMENU）。
* 如果兩個條件都成立，就讓程式退出。
* 如果只按了 F4，沒按 Alt，就吐槽他。

⚠️ 注意：每個 `{` 都要搭配一個 `}`，否則會報錯。

---

### 📘 7.1.9 多條件的 if：用邏輯運算子（and、or、not）

有時候，我們要在同一個 if 裡判斷多個條件，就要用「邏輯運算子」。

#### ✅ 同時滿足兩個條件：用 `&&`（and）

```bgt
if((key_down(KEY_LMENU)) && (key_pressed(KEY_F4)))
{
  exit(); // Alt+F4 同時成立才會退出
}
```

📝 **備註：**

* `&&` 的意思是「而且」。
* 要兩邊都為 true，整個條件才會成立。

#### ✅ 滿足任一條件：用 `||`（or）

```bgt
if((key_down(KEY_LMENU)) || (key_pressed(KEY_F4)))
{
  exit(); // 只要 Alt 或 F4 有其中一個成立就會退出
}
```

📝 **備註：**

* `||` 的意思是「或者」。
* 只要有一邊是 true，就會執行。

---

### 📘 7.1.10 not 運算子（!）：反過來判斷

你也可以用 `!` 來表示「不是」、「不成立」。

🔽 例子：

```bgt
if(!key_down(KEY_LMENU))
{
  // 如果沒有按 Alt 鍵，才會執行這段
}
```

📝 **備註：**

* `!` 是「反邏輯」的意思。
* 假設原本條件是 true，加了 `!` 就會變成 false。

---

### 📘 7.1.11 小心：`!` 不是用來比較兩個東西！

有些人會搞混，誤以為 `!` 可以拿來比較兩個變數。

❌ 錯誤寫法（會報錯）：

```bgt
if(!my_var1 = my_var2)
```

✅ 正確寫法（用來比較不相等）：

```bgt
if(my_var1 != my_var2)
```

📝 **補充說明：**

* `!=` 代表「不等於」。
* 它會傳回 true（不一樣）或 false（一樣）。
* `!` 是「反轉布林值」，不能直接拿來比兩個變數是否不一樣。

---

### 📘 7.1.12 什麼是布林變數（boolean）？

布林變數只能存兩種值：`true`（真）、`false`（假）。

🔽 例如：

```bgt
bool has_weapon = true;

if(has_weapon)
{
  // 如果玩家有武器，就做這件事
}
```

📝 **備註說明：**

* 如果 `has_weapon` 是 `true`，那整個條件就成立。
* 如果是 `false`，條件就不成立，不會執行。

等於是在問：「has\_weapon 是真的嗎？」如果是，就執行大括號內的程式。

---

### 📘 7.1.13 布林變數不能拿來重新命名

像 `true` 和 `false` 是語言內建的關鍵字，不能拿來當變數名。

❌ 不能寫：

```bgt
false = 5; // 錯誤！false 是關鍵字，不能改它
```

✅ 正確寫法：

```bgt
bool ready = false;
```

---

### 7.1.14 work

---

#### 🧠 初學者專用：if 判斷練習題

---

##### ✅ 題目 1：健康值警告

🔸 題目說明：寫一段程式碼，如果變數 `health` 小於 20，就顯示警告訊息「危險！血量太低！」。
🔸 目的：練習基本 if 判斷式。

```bgt
int health = 15;

// 在這裡加入 if 判斷
```

---

##### ✅ 題目 2：買東西要多少錢

🔸 題目說明：如果 `money` 大於等於 100，就顯示「你有足夠的錢買道具！」，否則顯示「錢不夠，請努力賺錢！」
🔸 目的：練習 if-else 的用法。

```bgt
int money = 80;

// 在這裡加入 if-else 判斷
```

---

##### ✅ 題目 3：是否成年

🔸 題目說明：請隨機產生一個 5 到 50 之間的年齡，並顯示「你是未成年」或「你已成年」。
🔸 目的：練習變數＋if 判斷＋字串拼接。

```bgt
int age = random(5, 50);

// 判斷 age 是否小於 18
```

---

##### ✅ 題目 4：登入系統

🔸 題目說明：設定一個布林變數 `is_logged_in`。如果它是 true，就顯示「歡迎使用者」，否則顯示「請先登入」。
🔸 目的：練習布林值與 if 判斷。

```bgt
bool is_logged_in = false;

// 在這裡加入 if 判斷
```

---

##### ✅ 題目 5：是否有鑰匙可以開門

🔸 題目說明：設定一個布林變數 `has_key`。如果它是 true，就顯示「你打開了門」，否則什麼都不做。
🔸 目的：練習只有單一條件、沒有 else 的情況。

```bgt
bool has_key = true;

// 寫一個只有 if 的條件判斷
```

---

#### 💡 進階挑戰題（結合邏輯運算子）

---

##### 🔶 題目 6：按下 Alt+F4 才能離開

🔸 題目說明：如果玩家同時按下 Alt 鍵（`key_down(KEY_LMENU)`）以及 F4 鍵（`key_pressed(KEY_F4)`），則執行離開程式 `exit()`。
🔸 目的：練習使用 `&&` 做多條件判斷。

```bgt
// 判斷是否同時按下 Alt + F4
```

---

##### 🔶 題目 7：按下任一鍵就開始遊戲

🔸 題目說明：如果玩家按下空白鍵（`key_pressed(KEY_SPACE)`）或 Enter 鍵（`key_pressed(KEY_RETURN)`），顯示「遊戲開始！」
🔸 目的：練習使用 `||` 或的邏輯判斷。

```bgt
// 判斷是否按下 空白鍵 或 Enter 鍵
```

---

##### 🔶 題目 8：如果沒有按住 Ctrl 鍵就提示「請按住 Ctrl」

🔸 題目說明：用 `!` 判斷是否「沒有」按住 Ctrl 鍵（`key_down(KEY_LCONTROL)`）。
🔸 目的：練習 `!` 否定運算子。

```bgt
// 使用 if(!...) 判斷
```

---
#### 🧩 7.2. Switch 和 Case 判斷

`switch...case` 和 `if` 判斷式非常相似，
**但它的用途是：當你有很多「不同的固定條件」要判斷時，它會讓程式碼更清楚、更好管理**。

---

##### 🧪 範例說明

```bgt
int health;
double energy;

switch(health)
{
    case 100:
        energy = 100;
        break;
    case 90:
        energy = 89;
        break;
    case 80:
        energy = 78;
        break;
    case 70:
        energy = 67;
        break;
    case 60:
        energy = 56;
        break;
    // 更多條件可以繼續加在這裡
}
```

---

##### 🧠 7.2.1 語法結構

```bgt
switch(變數)
{
    case 數值1:
        // 做某件事
        break;
    case 數值2:
        // 做某件事
        break;
    ...
    default:
        // 如果都沒有符合上面的條件，做這件事
        break;
}
```

---

##### 📌 關鍵詞簡單解釋：

| 關鍵字       | 意思與用途                       |
| --------- | --------------------------- |
| `switch`  | 這是整個條件判斷的開始，要放一個變數或運算式來判斷   |
| `case`    | 每一個要判斷的條件值，都用一個 case 開頭     |
| `break`   | 跳出這個 case，避免執行到其他 case 的程式碼 |
| `default` | 如果沒有任何 case 符合，就會執行這一段      |

---

##### 🧃 7.2.2 為什麼要用 break？

如果你省略 `break`，那電腦會繼續執行下一個 `case` 的內容，像這樣：

```bgt
switch(health)
{
    case 100:
        energy = 100;
    case 90:
        energy = 89;
}
```

假設 health 是 100，結果 energy 會變成 89，因為沒有 `break`，會往下繼續執行。這叫做 **「落入（fall-through）」**，有時可以故意這樣做，但一般建議都加上 `break`。

---

##### 🌟 7.2.3 加入 default 預設情況

```bgt
switch(health)
{
    case 100:
        energy = 100;
        break;
    case 90:
        energy = 89;
        break;
    case 80:
        energy = 78;
        break;
    default:
        energy -= 0.5;
        break;
}
```

這代表除了 100、90、80 以外的情況，能量會減少 0.5。

---

##### 🔍 7.2.4 switch 裡能放什麼？

```bgt
switch(變數或運算式)
```

可以放一個計算結果的表達式，例如：

```bgt
switch(number % 100)
```

這代表我們會根據 number 除以 100 的「餘數」來決定要做什麼事。

❌ 但 `case` 裡面 **不可以放變數或條件式**，像這樣是錯的：

```bgt
case number:      // ❌ 不行
case n < 5:       // ❌ 不行
```

✅ 每個 `case` 一定要是固定的常數，例如：

```bgt
case 100:
case 50:
```

---

##### 🧱 7.2.5 注意事項總整理：

1. 每個 case 要用 `break` 結束，除非你想「刻意執行多個 case」。
2. `default` 是選擇性的，但加上它會更穩健。
3. `switch` 裡的表達式結果要是「數值」。
4. `case` 裡只能放固定值，不能是變數或運算式。
5. 每個 case 的值必須唯一，不能重複。
6. 你可以巢狀（nest）switch 語句，也就是 switch 裡再放 switch。

> 「如果你在寫 if 時發現一堆 == 判斷，而且對同一個變數判斷，那就該改用 switch 了！」

---

##### work

---

##### 🎯【練習題 1：星座運勢】（初級）

使用者輸入一個數字（1\~12），代表月份，根據輸入顯示該月份的星座名稱。

🔹 範例輸入：`3`
🔹 範例輸出：`你是雙魚座`

---

##### 🎯【練習題 2：遊戲選單】（初級）

模擬一個主選單：

```
1. 開始新遊戲
2. 載入進度
3. 設定
4. 離開
```

根據使用者輸入的選項，顯示不同的訊息。用 `switch` 完成。

---

##### 🎯【練習題 3：經驗值等級系統】（中級）

輸入一個等級（1\~5），根據等級顯示稱號，例如：

| 等級 | 稱號  |
| -- | --- |
| 1  | 初學者 |
| 2  | 冒險者 |
| 3  | 老手  |
| 4  | 勇者  |
| 5  | 傳說  |

如果超過 5，顯示「等級未知」。

---

##### 🎯【練習題 4：攻擊武器選擇】（中級）

根據玩家選的武器 ID，給出武器名稱與攻擊力：

```
1 → 劍：攻擊力 20
2 → 弓：攻擊力 15
3 → 魔杖：攻擊力 25
4 → 匕首：攻擊力 10
```

請輸入武器 ID，用 `switch` 顯示結果。

---

##### 🎯【練習題 5：音樂節奏打擊點數計算】（進階）

使用者輸入評價等級（S、A、B、C、D），顯示對應的加分數值。

| 評價 | 分數加成 |
| -- | ---- |
| S  | +100 |
| A  | +80  |
| B  | +50  |
| C  | +30  |
| D  | +0   |

🔹 提示：這題是文字類型的 switch（也可練習用 `char` 或 `string`）

---

##### 🎯【練習題 6：天氣系統效果】（進階）

輸入天氣狀況代碼（0\~4）：

| 代碼 | 天氣 | 效果            |
| -- | -- | ------------- |
| 0  | 晴天 | 無效果           |
| 1  | 雨天 | 攻擊減少 10%      |
| 2  | 雷雨 | 攻擊減少 15%，速度下降 |
| 3  | 風沙 | 命中率下降         |
| 4  | 暴雪 | 攻擊與速度各下降 20%  |

如果輸入其他數字，顯示「未知天氣」。

---

#### ✅ 想法提示：

這些題目幫助你練習以下技能：

* `switch` 的基本語法
* `break` 和 `default` 的用法
* 判斷整數、字串、甚至是表達式
* 根據輸入做出分類行為

---

在 BGT（Blastbay Game Toolkit）中，輸入文字是透過 `edit_box()` 函數來完成的。這個函數會彈出一個編輯視窗，讓玩家輸入內容，然後把結果回傳回來。

---

✅【基本語法】

```bgt
string user_input = edit_box("請輸入你的名字：");
```

這行程式的意思是：

* 顯示一個輸入框，提示玩家「請輸入你的名字：」
* 等待玩家輸入文字
* 把輸入的文字存到變數 `user_input` 裡

---

📌【完整範例】

```bgt
void main()
{
    string name = edit_box("請輸入你的名字：");
    alert("你好！", "歡迎你，" + name + "！");
}
```

🗣️ 執行效果：

1. 彈出輸入框讓使用者輸入名字
2. 接著顯示一個對話框說：「歡迎你，使用者名字！」

---

🧠【補充說明】

* `edit_box()` 是同步的，會等使用者輸入完才繼續執行程式。
* 如果使用者什麼都不輸入直接按 Enter，它會回傳空字串（`""`）。
* `edit_box()` 只能輸入一行文字（不支援換行）。

---

🔐【常見用途】

* 要輸入角色名稱、密碼、暱稱
* 設定選項（像是玩家數、難度）
* 建立聊天室暱稱、輸入命令等等

---
## 8. **迴圈（Loops）**

認識什麼是迴圈

在你學會 `if` 條件判斷後，接下來要學的就是「**迴圈（Loop）**」這個非常重要的概念。其實它們有點像，因為兩者都會根據某個「條件」來決定是否執行某段程式碼。

但不同的是：

* `if` 是**只檢查一次**，如果條件成立就執行一次。
* `loop` 則是**持續檢查條件**，只要還符合條件，就一直執行下去。

---

在遊戲中迴圈的用途：

在遊戲裡，迴圈是非常常見的工具。例如：

* 不停地偵測玩家按下的按鍵
* 檢查角色是否死亡
* 不斷更新畫面或音效
* 每隔一段時間增加分數或扣血

你幾乎可以想成「遊戲本體」就是一個超大的無限迴圈，讓整個世界不斷運作。

---

有哪三種常用的迴圈？

這章會介紹三種在 BGT 常見的迴圈語法：

| 類型           | 說明                       |
| ------------ | ------------------------ |
| `while`      | 只要條件成立就會一直執行             |
| `do...while` | 至少執行一次，再檢查條件             |
| `for`        | 通常用在「做固定次數」的情況，例如重複 10 次 |

---

先理解基本觀念

你可以把迴圈想像成這樣的流程：

```plaintext
重複以下動作：
    - 檢查條件是不是成立？
    - 如果是，就執行某段程式碼
    - 再回到第一步
    - 如果不是，就跳出迴圈
```

---

### 🔹 8.1：`while` 迴圈（while loops）

#### 🧾 基本概念說明：

當你想要讓某段程式碼「重複執行」直到某個條件成立，就會使用 `while` 迴圈。它的結構是：

```bgt
while (條件)
{
    // 重複執行的內容
}
```

只要「條件成立」，大括號 `{}` 裡的程式碼就會不斷執行。等條件不成立，才會跳出這個迴圈。

---

#### ✅ 第一個範例解說：

```bgt
while(key_pressed(KEY_ESCAPE)==false)
{
    wait(5);
}
```

🔍 **逐行解釋：**

1. `while(...)`：這表示要開始一個迴圈。
2. `key_pressed(KEY_ESCAPE)==false`：這是條件，意思是「當沒有按下 ESC 鍵時，就繼續執行」。
3. `wait(5);`：讓程式暫停 5 毫秒。

🔔 **為什麼要用 `wait(5)`？**

如果你不加這行，CPU 會高速不斷地檢查鍵盤，會造成 100% 使用率，導致電腦過熱或卡頓。所以**一定要在長時間執行的迴圈中加入短暫的等待時間**，這樣才能節省電腦資源。

---

#### 🧮 第二個範例：重複執行 1000 次

```bgt
int x=0;
while(x<1000)
{
    // 在這裡放你想執行的程式
    x++;
}
```

📌 解說：

* `x=0`：先定義變數 `x` 為 0。
* `x<1000`：只要 `x` 還小於 1000，就一直重複執行。
* `x++`：每次迴圈讓 `x` 加 1，這是關鍵！不然會變成無限迴圈。

這段程式碼會讓裡面的指令**執行 1000 次**，`x` 從 0 一直到 999。

---

#### 🔢 第三個範例：印出 0 到 10 的數字

```bgt
int x=0;
string numbers="";
while(x<=10)
{
    numbers+=x;
    if(x<10)
    {
        numbers+=" ";
    }
    x++;
}
alert("Printing numbers 0 to 10", numbers);
```

📌 這段程式的目的是顯示這樣的字串：「`0 1 2 3 4 5 6 7 8 9 10`」

* `numbers+=x`：把 `x` 的數字轉成字串，加到 `numbers` 裡。
* `if(x<10)`：為了避免最後一個數字後面還有空格，這裡做條件控制。
* `x++`：記得讓 `x` 增加，否則永遠卡在 0。

---

#### ✨ 縮短版的寫法：

```bgt
int x=0;
string numbers="";
while(x<=10)
{
    numbers+=x++;
    if(x<=10)
    {
        numbers+=" ";
    }
}
alert("Printing numbers 0 to 10", numbers);
```

🧠 這段寫法更精簡，因為 `x++` 會先使用 `x` 的原值，再讓它自動加 1，非常適合有經驗的開發者使用。

---

#### 📌 小結與新手須知

| 重點               | 說明                                  |
| ---------------- | ----------------------------------- |
| 什麼是 while 迴圈？    | 當條件為真，就不斷執行區塊中的程式                   |
| 要記得加 wait()      | 避免 CPU 過載，通常用 `wait(5)` 足夠          |
| 要讓條件會變化          | 如果條件永遠都成立，會變成無限迴圈                   |
| while 是用來「等事情發生」 | 像是按鍵、倒數、某變數達到目標值等                   |
| `x++` 是什麼？       | 把 `x` 加 1，等同於 `x = x + 1`，是迴圈中常見的動作 |

#### work
##### 🧪 題目 1：輸出從 1 到 5 的數字

```bgt
int x = 1;
while(x <= 5)
{
    alert("現在的數字是", x); // 輸出：1, 2, 3, 4, 5
    x++;
}
```

---

##### 🧪 題目 2：倒數從 5 到 1

```bgt
int x = 5;
while(x >= 1)
{
    alert("倒數中：", x); // 輸出：5, 4, 3, 2, 1
    x--;
}
```

---

##### 🧪 題目 3：印出 3 的倍數，從 3 到 30

```bgt
int x = 3;
while(x <= 30)
{
    alert("3 的倍數：", x); // 輸出：3, 6, 9, 12, ..., 30
    x += 3;
}
```

---

##### 🧪 題目 4：累加總和直到超過 20

```bgt
int sum = 0;
int x = 1;
while(sum <= 20)
{
    sum += x;
    x++;
}
alert("最後的總和是", sum); // 輸出：21（因為 1+2+3+4+5+6 = 21）
```

---

##### 🧪 題目 5：直到使用者按下 ESC 鍵才結束

```bgt
while(key_pressed(KEY_ESCAPE) == false)
{
    alert("請按 ESC 鍵結束", "等你中...");
    wait(500); // 避免 CPU 爆轉，等待 0.5 秒
}
```

---

##### 🧪 題目 6：找出第一個能被 7 整除且大於 50 的數

```bgt
int x = 51;
while(true)
{
    if(x % 7 == 0)
        break;
    x++;
}
alert("找到第一個能被 7 整除的數是", x); // 輸出：56
```

---

### 🔹 8.2：`do...while` 迴圈

#### 📌 什麼是 `do...while`？

`do...while` 跟我們剛剛學過的 `while` 很像，但有一個**最關鍵的差別**：

> `do...while` **一定會先執行一次裡面的程式碼，然後才檢查條件是否成立**。

---

#### 🔍 範例：

```bgt
do
{
    wait(5);
}
while(!key_pressed(KEY_ESCAPE));
```

這段的意思是：

1. **先**讓程式等待 5 毫秒。
2. 再檢查有沒有按下 ESC 鍵。
3. **如果還沒按下，就繼續重複。**

---

#### 📘 關鍵語法結構：

```bgt
do {
    // 先做這些事
}
while (條件); // 檢查條件是否要繼續重複
```

✅ 注意這裡的 `while (條件)` 後面有 **分號 `;`**！這是一定要加的，因為這是一個完整的語句結尾。

---

#### ❗️補充語法知識：驚嘆號 `!`

這裡用到這樣的寫法：

```bgt
while(!key_pressed(KEY_ESCAPE));
```

這其實等同於：

```bgt
while(key_pressed(KEY_ESCAPE)==false);
```

✅ `!` 是「邏輯非」，意思是「相反的意思」。所以 `!true` 就是 `false`，`!false` 就是 `true`。

---

#### ⚔️ 和 `while` 的最大不同

| 類型           | 執行順序                | 可能執行 0 次？   |
| ------------ | ------------------- | ----------- |
| `while`      | **先檢查條件**，再執行       | ✅ 有可能       |
| `do...while` | **先執行一次**，再檢查是否繼續執行 | ❌ 一定會至少執行一次 |

這種寫法常用在：

* 玩家要輸入選項前先顯示一次提示。
* 遊戲進入畫面至少顯示一次再等玩家按鍵。
* 必須先初始化東西，再來檢查是否重複。

---

#### 📦 小結

* `do...while` 的特點是：**先執行、後判斷**。
* `while` 是：**先判斷、再執行**。
* 使用 `!` 可以表達「反向條件」。
* 記得 `while(...)` 之後要加分號 `;`！

---

#### work

##### 🧪 題目 1：請使用者按下 ESC 鍵才結束程式

```bgt
do
{
    alert("提示", "請按 ESC 鍵結束");
    wait(500); // 等待 0.5 秒，避免 CPU 過度運作
}
while(!key_pressed(KEY_ESCAPE)); // 如果還沒按下 ESC，就繼續執行
```

🔍 **重點說明**：

* `do` 代表先執行一次。
* `while()` 內是條件，這裡的 `!key_pressed(KEY_ESCAPE)` 表示「只要還沒按 ESC，就繼續」。

---

##### 🧪 題目 2：重複詢問使用者是否要繼續

```bgt
string answer;
do
{
    answer = input_box("輸入", "要繼續嗎？輸入 yes 來繼續");
}
while(answer == "yes");
```

🔍 **重點說明**：

* `input_box()` 會讓使用者輸入文字。
* 如果輸入的是 "yes"，就會再問一次；其他輸入就會結束。

---

##### 🧪 題目 3：一直顯示計數，直到使用者按下空白鍵

```bgt
int count = 1;
do
{
    alert("計數器", count);
    count++;
    wait(300); // 延遲 0.3 秒
}
while(!key_pressed(KEY_SPACE)); // 沒按空白鍵就繼續
```

🔍 **重點說明**：

* 每次顯示目前數字。
* 使用者按下空白鍵時才會結束。

---

##### 🧪 題目 4：播放提示音直到按 Enter 為止

```bgt
do
{
    play_sound("beep.ogg");
    wait(1000); // 每秒播放一次
}
while(!key_pressed(KEY_RETURN)); // 沒按 Enter 就繼續
```

📝 **備註**：

* 要記得你要有 `beep.ogg` 這個音效檔，或改成你有的音效。

---

##### 🧪 題目 5：讓玩家輸入密碼，直到正確為止

```bgt
string password;
do
{
    password = input_box("請輸入密碼", "密碼是 abc123");
}
while(password != "abc123");

alert("成功", "密碼正確！");
```

🔐 **說明**：

* 這題可以模擬登入。
* 錯的話會一直問，直到輸入對為止才會跳出提示「密碼正確」。

---

### 🔷 8.3：`for` 迴圈

#### ✅ 為什麼要用 `for`？

前面學過的 `while` 和 `do...while` 都可以重複執行程式碼，但如果你只是想要「從 1 數到 10」，或者「執行 100 次」，那 `for` 迴圈會**更簡潔、更清楚**。

---

#### 📘 語法結構

```bgt
for(int x = 0; x <= 10; x++)
{
    // 這段程式碼會執行 11 次，x 從 0 到 10
}
```

這一行裡面有三個部分，用分號隔開：

1. `int x = 0;` → **初始化**：設定一個變數，從哪個數字開始。
2. `x <= 10;` → **條件判斷**：只要這個條件是 `true`，就繼續執行。
3. `x++` → **每次執行完後的動作**：這裡是讓 x 加 1。

---

#### 🧠 等於下面這個 `while` 版本：

```bgt
int x = 0;
while(x <= 10)
{
    // 程式碼
    x++;
}
```

你會發現：`for` 只是把這個寫法縮短成一行而已，但更容易閱讀和維護！

---

#### 🔄 進階寫法：不只是 `+1`

你可以做任何你想要的事情，例如乘以 2：

```bgt
for(x = 1; x < 1000; x *= 2)
{
    // 每次 x 都會變成原來的兩倍
}
```

x 會變成 1 → 2 → 4 → 8 → 16 → ... → 512 → 下一次會是 1024，不符合條件就停了。

---

#### ✨ 使用時機

* 遍歷清單或陣列（未來會學）
* 重複固定次數的任務
* 跑關卡、計算分數、輸出表格
* 自動生成東西（像音效、敵人）

---

#### 🔍 `for` 的彈性

你不一定要從 0 開始，也不一定要用 `x++`，例如：

```bgt
for(int i = 10; i >= 0; i--)
{
    // 倒數計時：10 到 0
}
```

或者

```bgt
for(int i = 1; i <= 5; i+=2)
{
    // i 是 1, 3, 5
}
```

---

#### 🛠 小提醒

* `for` 迴圈裡的變數如果是用 `int x = 0` 宣告的，那這個變數只在 `for` 裡面有效。
* 如果你已經在外面宣告過 `x`，也可以直接寫成：

```bgt
int x = 0;
for(x = 0; x <= 10; x++)
```

---

#### 📦 總結

| 名稱     | 說明                |
| ------ | ----------------- |
| for 迴圈 | 適合「固定次數」的重複任務     |
| 語法     | `for(初始; 條件; 更新)` |
| 優點     | 一行搞定控制，簡潔清楚       |
| 進階用法   | 支援倒數、乘法遞增、變動步長等等  |

---

### work
#### 🎯 題目 1：顯示 1 到 10 的數字

```bgt
string result = "";
for(int i = 1; i <= 10; i++) // 從 1 加到 10
{
    result += i + " "; // 把數字加到字串裡，每次加一個空格
}
alert("題目 1", result); // 顯示 1 2 3 4 5 6 7 8 9 10
```

---

#### 🎯 題目 2：計算 1 到 100 的總和

```bgt
int sum = 0;
for(int i = 1; i <= 100; i++) // 每次把 i 加到 sum 裡
{
    sum += i;
}
alert("題目 2", "總和是：" + sum); // 顯示 5050
```

---

#### 🎯 題目 3：顯示偶數（2 到 20）

```bgt
string evens = "";
for(int i = 2; i <= 20; i += 2) // 每次加 2
{
    evens += i + " ";
}
alert("題目 3", evens); // 顯示 2 4 6 8 ... 20
```

---

#### 🎯 題目 4：從 10 倒數到 1

```bgt
string countdown = "";
for(int i = 10; i >= 1; i--) // 每次減 1
{
    countdown += i + " ";
}
alert("題目 4", countdown); // 顯示 10 9 8 ... 1
```

---

#### 🎯 題目 5：計算所有奇數的平方，從 1 到 9

```bgt
string result = "";
for(int i = 1; i < 10; i += 2) // 奇數：1, 3, 5, 7, 9
{
    int square = i * i;
    result += i + "^2 = " + square + "\n";
}
alert("題目 5", result); // 顯示每個奇數的平方
```

---

#### 🎯 題目 6：數字從 1 開始，每次乘 2，直到小於 1000

```bgt
string output = "";
for(int i = 1; i < 1000; i *= 2) // 1, 2, 4, 8, 16, ...
{
    output += i + " ";
}
alert("題目 6", output); // 顯示 1 2 4 8 16 32 64 128 256 512
```



---

### 🔷 8.4：`break` 和 `continue`

---

#### ✅ `while(true)` 是什麼意思？

```bgt
while(true)
{
    // 這裡的東西會無限執行下去！
}
```

這種寫法代表「**無限迴圈**」，永遠都會執行，因為 `true` 永遠都是真的。但我們不會讓它真的跑到電腦壞掉 😂，我們會用 `break` 來中斷它！

---

#### 🧱 `break` 是什麼？

`break` 就是**立刻跳出整個迴圈**，後面不用管條件了。

🔍 **範例：**

```bgt
int i = 0;
while(true)
{
    if(i == 5)
        break; // 當 i 等於 5 時，中止這個 while 迴圈

    alert("目前是第 " + i + " 次");
    i++;
}
```

上面這段程式會顯示 0 到 4 共五次，然後就跳出迴圈了。

---

#### 🔄 `continue` 是什麼？

`continue` 是**跳過這一輪，直接進入下一輪**。

🔍 **範例：**

```bgt
for(int i = 0; i < 10; i++)
{
    if(i == 3)
        continue; // 當 i 是 3，就跳過後面的程式碼

    alert("i = " + i);
}
```

這段程式會顯示：

```
i = 0
i = 1
i = 2
i = 4
i = 5
...
i = 9
```

中間跳過了 `i=3`。

---

#### 🧠 `break` 和 `continue` 的差別

| 關鍵字        | 功能             | 效果                  |
| ---------- | -------------- | ------------------- |
| `break`    | 完全跳出迴圈，後面不再執行  | 整個迴圈結束              |
| `continue` | 跳過本次，立刻進入下一次迴圈 | 本輪後面的程式碼不執行，直接繼續下一輪 |

---

#### 🎯 什麼時候會用到？

* `break`: 玩家生命歸 0、敵人打敗、檔案讀完了...
* `continue`: 空白行不要處理、錯誤資料直接跳過、某些條件不成立就略過...

---

#### 🧱 巢狀迴圈的小提醒

```bgt
while(true)
{
    while(true)
    {
        break;
    }
    // break 只會跳出「最內層」的迴圈
}
```

如果你有**多層巢狀迴圈**，`break` 只會跳出你正在寫的那一層。不是整個外層迴圈都會被中止。

---

#### ✅ 總結一下：

| 關鍵字        | 說明               |
| ---------- | ---------------- |
| `break`    | 強制跳出整個目前所在的迴圈    |
| `continue` | 跳過本輪剩下的程式碼，繼續下一輪 |

---

### work

#### 🎯 題目 1：遇到特定數字就中斷（`break`）

請用 `for` 迴圈列出數字 1 到 100，但當遇到 42 就停止顯示。

```bgt
string result = "";
for(int i = 1; i <= 100; i++)
{
    if(i == 42) // 如果遇到 42
    {
        break; // 停止整個迴圈
    }
    result += i + " ";
}
alert("題目 1", result); // 顯示 1 到 41
```

---

#### 🎯 題目 2：跳過特定數字（`continue`）

列出 1 到 10 的數字，但跳過 5，不要顯示它。

```bgt
string result = "";
for(int i = 1; i <= 10; i++)
{
    if(i == 5)
    {
        continue; // 跳過這次，後面的程式碼不執行
    }
    result += i + " ";
}
alert("題目 2", result); // 顯示 1 2 3 4 6 7 8 9 10
```

---

#### 🎯 題目 3：一直等到使用者按下 ESC 才跳出

```bgt
alert("題目 3", "請按 ESC 結束程式");

while(true) // 無窮迴圈
{
    if(key_pressed(KEY_ESCAPE)) // 如果按下 ESC
    {
        break; // 跳出迴圈
    }
    wait(10); // 等待一下，不然 CPU 爆炸
}
alert("結束", "你按了 ESC，迴圈結束");
```

---

#### 🎯 題目 4：計算 1 到 20 的偶數總和，但如果是 14 就中斷

```bgt
int sum = 0;
for(int i = 1; i <= 20; i++)
{
    if(i == 14) // 如果遇到 14，就結束
    {
        break;
    }
    if(i % 2 == 0) // 只加偶數
    {
        sum += i;
    }
}
alert("題目 4", "總和（遇到 14 前的偶數）：" + sum); // 顯示偶數加總，不包含 14
```

---

#### 🎯 題目 5：列出 1 到 20 中，不能被 3 整除的數字

```bgt
string result = "";
for(int i = 1; i <= 20; i++)
{
    if(i % 3 == 0)
    {
        continue; // 被 3 整除的數字跳過
    }
    result += i + " ";
}
alert("題目 5", result); // 顯示除了 3, 6, 9, 12... 以外的數字
```

---

### 8.5 進階練習
#### 🎯 進階題目 1：猜數字小遊戲（使用 while + if）

**規則**：
電腦設定一個數字（例如 42），玩家不斷輸入數字猜，直到猜中為止，每猜一次會提示「太大」或「太小」。

```bgt
int answer = 42; // 正確答案
int guess = -1;  // 玩家猜的數字

while(guess != answer)
{
    guess = prompt_number("猜數字", "請輸入你猜的數字：");

    if(guess < answer)
    {
        alert("提示", "太小了！");
    }
    else if(guess > answer)
    {
        alert("提示", "太大了！");
    }
}
alert("恭喜", "你猜對了！");
```

---

#### 🎯 進階題目 2：輸入密碼直到正確為止（使用 do while）

```bgt
string correct_password = "abc123";
string input = "";

do
{
    input = prompt("請輸入密碼", "密碼：");
}
while(input != correct_password);

alert("成功", "密碼正確，歡迎登入！");
```

---

#### 🎯 進階題目 3：顯示前 20 個質數（只能被 1 和自己整除）

這題會用到巢狀 for 迴圈與 break

```bgt
string result = "";
int count = 0;
int number = 2;

while(count < 20)
{
    bool is_prime = true;
    for(int i = 2; i < number; i++)
    {
        if(number % i == 0)
        {
            is_prime = false;
            break;
        }
    }

    if(is_prime)
    {
        result += number + " ";
        count++;
    }

    number++;
}
alert("前 20 個質數", result);
```

---
## 9. 陣列與字典（第 1 部分）

到目前為止，我們已經學過變數的基本用法，例如怎麼操作變數、它們在寫程式時可以做哪些事。不過你很快就會發現一個大問題：當你在開發一個中型以上的遊戲時，可能會出現超級多的變數要管理，非常混亂。

舉個例子，如果你寫一個有 50 格地圖的遊戲，每次玩家擲骰子，就會前進一些格數，而每個格子代表不同事件。例如：1 表示後退三格、2 表示停在原地、3 表示前進三格。這樣一來你就要寫：

```bgt
int board0=2;
int board1=2;
int board2=2;
...
int board14=1;
```

這樣一路寫到 board49，總共要寫 50 行，光是看就覺得頭痛。如果是橫向卷軸遊戲，地圖格數可能是 300，那就更可怕。除了寫起來很累，之後你還要用 300 個 if 判斷去決定現在是哪個格子，這根本就是災難！

這時候就可以用「陣列」（array）來幫忙啦！

---

### 陣列的基本觀念

簡單來說，陣列就是一組變數的集合。你可以把它想像成一個清單，每一格都可以存一個值，而且這些值可以用「編號」來取出。這個編號我們稱為「索引」（index），從 0 開始算。

舉個例子：

```bgt
int[] board(50); // 建立一個陣列，裡面有 50 個整數
for(int x=0; x<50; x++)
{
  board[x]=2; // 將每一格的值都設成 2
}
```

這裡出現了幾個重點：

* `int[] board(50);`：這行表示建立一個「整數陣列」，裡面有 50 格。
* `board[x] = 2;`：這表示第 x 格的值設為 2（每次迴圈跑一格）。
* 索引是用方括號 `[ ]`，不是小括號 `( )`。

你應該注意到，我們的格子從 0 開始編號，這是因為在程式語言中，陣列的第一個位置都是 0。如果你寫 `board[50]`，那會超出陣列範圍，程式會在執行的時候報錯，所以記得陣列最大只能用到 `49`。

---

### 多維陣列（進階）

如果你想要做棋盤或地圖這類「二維格子」，怎麼辦？這時候可以用「二維陣列」，像這樣：

```bgt
int[][] chessboard;
chessboard.resize(8);
for(int i=0; i<8; i++)
{
  chessboard[i].resize(8); // 每一列也要 resize
}
```

這樣就建立了一個 8x8 的棋盤，像西洋棋一樣。你可以用 `chessboard[0][0]` 來指定最左上角的格子，用 `chessboard[7][7]` 指最右下角。

還可以做三維的：

```bgt
int[][][] board;
board.resize(3);
for(int i1=0; i1<3; i1++)
{
  board[i1].resize(3);
  for(int i2=0; i2<3; i2++)
  {
    board[i1][i2].resize(3);
  }
}
```

這樣就建立了一個 3x3x3 的三維格子，可以模擬上下左右、前後移動的 3D 地圖。

BGT 目前最多支援四維陣列，不過對一般遊戲來說三維已經很夠用了。

---
### 陣列的實用函數與操作

陣列雖然很方便，但你常會想知道它目前到底有幾個項目，也就是「長度」，這時候可以用：

```bgt
int len = board.length();
```

這行會取得 `board` 陣列的目前長度，也就是它有幾個元素。你可以用這個方法來當作迴圈的上限，像這樣：

```bgt
for(int x=0; x<board.length(); x++)
{
  alert("第 " + x + " 格的內容是", board[x]);
}
```

如果你想改變陣列的長度，請用：

```bgt
board.resize(20); // 把原本陣列變成 20 格
```

這個會保留原本的內容，再新增（或刪除）格子來調整大小。如果你原本有 10 格，現在設成 20，就會新增 10 格補上預設值（整數預設是 0）。

---

### 陣列的另一種寫法（快速建立）

你也可以一開始就把內容一次寫出來，例如：

```bgt
int[] board = {1, 2, 3, 4, 5};
```

這行表示建立一個有 5 個整數的陣列，分別是 1 到 5，這寫法很常見。

同樣的，字串陣列也可以這樣寫：

```bgt
string[] names = {"Alice", "Bob", "Carol"};
```

這裡就建立了三個名字的清單，可以透過 `names[0]`、`names[1]` 來取用。

---

### 字串其實也是陣列！

很酷的是，在程式語言裡，「字串」其實也可以看作是「字元的陣列」。也就是說，你可以用 `[ ]` 取出某一個字元：

```bgt
string name = "BGT";
alert("第二個字元是", name[1]); // 結果會是 G
```

這裡的 `name[1]` 表示第二個字（因為從 0 開始），也就是 `G`。

---

### 字典 Dictionary（又稱 Map）

字典的用途是什麼呢？它跟陣列有點像，但最大的差別在於「索引」不是數字，而是你自己指定的「關鍵字（key）」。就像一本字典，你查的是「蘋果」，而不是第 12 頁。

先來看怎麼建立：

```bgt
dictionary dict;
dict["cat"] = "貓";
dict["dog"] = "狗";
```

這裡，我們把英文單字對應到中文，像是「cat」對應「貓」，這就很適合做翻譯字典、小型資料庫。

你也可以這樣用：

```bgt
dictionary players;
players["mingo"] = 80; // mingo 的血量是 80
```

之後用 `players["mingo"]` 就能查詢他的血量。這比陣列更有彈性，因為你不用記得數字，而是用名字就能取資料。

---

### 判斷資料是否存在

你可能會問：「如果我查一個沒加進字典的 key，會怎樣？」答案是：會報錯。

所以你應該這樣寫：

```bgt
if(dict.exists("cat"))
{
  alert("查詢結果", dict["cat"]);
}
else
{
  alert("錯誤", "找不到 cat");
}
```

這裡的 `.exists()` 可以用來檢查 key 是否存在，避免程式中斷。

---

### 刪除字典中的項目

如果你要刪除某筆資料，可以這樣寫：

```bgt
dict.erase("dog"); // 刪除 dog 這個 key
```

這樣會把 dog 對應的資料整筆移除。

---

### 小結

| 類型       | 說明           | 範例                  |
| -------- | ------------ | ------------------- |
| 陣列 array | 用數字索引        | `board[0] = 10`     |
| 字串       | 也是一種字元陣列     | `name[1] = "G"`     |
| 字典 dict  | 用文字索引，像資料庫一樣 | `dict["cat"] = "貓"` |

---

### 延伸練習建議：

1. 建立一個 10 格的陣列，儲存 1\~10，然後印出每個格子裡的值。
2. 製作一個英文到中文的字典，讓使用者輸入英文單字，就輸出對應的中文。
3. 嘗試用二維陣列來儲存一個 3x3 的九宮格遊戲畫面（可用 0 表示空格，1 表示 O，2 表示 X）。
4. 建立一個記錄玩家姓名和分數的字典，寫一個函數可以查詢、更新與列出所有成績。

---
## 10. 物件（Objects）與類別（Classes）

在使用 BGT 引擎開發遊戲時，「物件（Object）」是一項非常強大，而且絕對必要的功能。所以，請務必仔細閱讀這一章的內容。

你可以把「物件」想像成一種特別的變數，它不只可以像一般變數那樣儲存資料，還能擁有「自己的功能（函式）」，這些功能是專門為這個物件服務的。

再說得更白話一點：「物件」就像是一個小機器人，身上帶著自己的資料（例如生命值、速度、位置等），也會做一些事（例如移動、攻擊），這些動作就是內建在它身上的功能。

「類別（Class）」則是建立物件的藍圖或模版，當我們用這個模版去做出一個物件時，那就是「實例化」出一個物件。

為了讓你更清楚地了解什麼是物件，我們先來看個簡單的範例。

---
舉個例子：

```
sound ambience;
ambience.load("curry.ogg");
```

這兩行程式碼做了幾件事：

1. 它建立了一個新的物件，類型是 `sound`（音效）。
2. 這個音效物件的變數名稱叫做 `ambience`。
3. 它呼叫了 `ambience` 裡的一個功能（稱為方法），這個功能是 `load`，也就是「載入音效檔案」，載入的是 `curry.ogg` 這個檔案。

簡單來說，這段程式碼就像是在說：「嘿，我要建立一個叫做 `ambience` 的音效播放器，然後讓它去載入一個叫 `curry.ogg` 的音效檔案。」

---

當我們建立一個物件時，可以選擇給它一些「設定參數」，來決定這個物件的初始行為。不過也可以不給任何參數，像 `sound` 或 `timer` 這種類型的物件，就不需要傳參數也能直接建立。

舉個例子，這樣就可以建立一個計時器物件：

```
timer jumptime;
```

這樣就創建了一個計時器，名字叫做 `jumptime`。

---

每個物件都有「屬性（properties）」，這些屬性就像是物件身上的小資料，可以在使用期間去查詢或更改。

例如剛剛提到的 `sound` 音效物件，就有一個叫 `volume` 的屬性，代表音量大小。

你可以在播放音樂前，把音量設定為比原本小一半，例如：

```
sound ambience;
ambience.stream("curry.wav");
ambience.volume = -6;
```

這裡的 `stream` 表示要「串流播放」這段音樂，而 `volume = -6` 是把音量降低 6 分貝，這大概是原本音量的一半。

---

你也可以去**讀取**屬性的值來做判斷，例如：

```
if (ambience.volume > -10) {
  // 做一些事情
}
```

這意思是說：「如果音量大於 -10 分貝，就執行某些程式。」

但請注意，不是每個屬性都可以修改。有些只能查詢、有些只能在特定情況下修改，詳細內容可以查閱每種物件的「屬性說明表」。

---
物件除了有「屬性」之外，還會有「方法」，也就是可以幫你執行某些動作的「功能」。

你可以把方法想成是這個物件專屬的「指令」或「技能」，像是音效物件就有「播放」的功能，這些方法只能用在它自己這個物件上。

舉個例子，`sound` 物件有一個叫做 `play_wait` 的方法，它的意思是「播放這段音效，並且等音效播放完才繼續執行接下來的程式碼」。

我們把前面的範例繼續延伸一下，加上播放音效的動作：

```
sound ambience;
ambience.stream("curry.wav");
ambience.volume = -6;
ambience.play_wait();
```

這四行的意思是：

1. 建立一個音效物件 `ambience`。
2. 用串流方式載入音效檔 `curry.wav`。
3. 將音量設為 -6 分貝。
4. 播放音效，並等待它播放完。

你會發現，我們就是在對 `ambience` 這個物件下指令。方法的使用方式就跟一般的函式一樣，也是用括號 `()`，有些方法需要傳入參數，有些則不需要。像 `play_wait()` 就是不需要參數的。

---

再來一個例子，如果你想同時播放兩段不同的音效，也可以這樣做：

```
sound music1;
sound music2;
music1.load("a.ogg");
music2.load("b.ogg");
music1.play();
music2.play();
```

這樣 `music1` 和 `music2` 這兩個物件就會獨立運作，各自播放不同的音效。也就是說，不同的物件之間不會互相干擾。

---

另外，你也可以把物件當成參數傳來傳去，但請注意：

❗ **你應該傳遞的是「物件的參照（handle）」，而不是物件本身。**

這樣可以讓你不會不小心複製整個物件（那會浪費記憶體）。傳遞參照的方式是，在 `sound` 這個類型後面加上一個 `@` 符號：

```
sound@ play_sound(string filename) {
  sound the_sound;
  the_sound.load(filename);
  the_sound.play();
  return the_sound;
}
```

這裡 `sound@` 表示這是一個「音效物件的參照」。這個函式會回傳一個 `sound` 物件的參照，而不是整個物件本身。

接下來可以這樣用：

```
void main() {
  show_game_window("My Game");
  sound@ ambience = play_sound("curry.wav");
  ambience.volume = -6;
  @ambience = null; // 把參照清空
}
```

設定 `@ambience = null;` 的意思是「把這個參照釋放掉」，等同於把物件刪除，不會再佔用記憶體。

這樣的寫法可以幫你更有效率地管理記憶體，也避免太多不必要的複製。

---

### 自訂類別（Class）

到目前為止，我們用的物件（像是 `sound`）都是別人幫我們定義好的，但你可以**自己定義一種新的物件類型**，讓它擁有你想要的屬性和方法。

這在遊戲設計中非常實用，例如你可以定義一種「敵人」的類別，然後用這個類別來建立出很多不同的敵人角色。

#### 語法範例：

```bgt
class enemy {
  int health;
  int speed;
  int position;

  // 建構子：建立敵人時自動執行的初始化方法
  enemy() {
    health = 100;
    speed = 200;
    position = 0;
  }

  // 另一個建構子：可以自己傳參數來初始化
  enemy(int init_health, int init_speed, int init_pos) {
    health = init_health;
    speed = init_speed;
    position = init_pos;
  }

  // 方法：發射武器
  void fire_weapon() {
    alert("敵人", "敵人發射武器！");
  }

  // 方法：移動敵人
  void move(int direction) {
    position += speed * direction;
  }

  // 解構子：敵人死亡時會自動執行
  ~enemy() {
    alert("敵人", "敵人已經死亡！");
  }
}
```

---

### 補充說明：

* `class enemy`：我們定義了一個名叫 `enemy` 的類別。
* `health`、`speed`、`position` 是這個類別的屬性（也就是變數）。
* `enemy()` 是建構子，當你 `new` 出一個敵人時會自動執行。
* `~enemy()` 是解構子，當物件被釋放（或消失）時會執行，用來清理或提示。
* `fire_weapon()` 與 `move()` 是方法，也就是你能對這個敵人下的指令。

---

### 如何使用這個類別？

```bgt
void main() {
  enemy robot(); // 建立一個敵人 robot
  robot.fire_weapon(); // 讓敵人發射武器

  while(robot.health > 0) {
    alert("敵人狀態", "目前血量：" + robot.health);
    robot.health -= 50;
  }

  // 當跳出迴圈後，物件會自動釋放，執行 ~enemy()，顯示敵人已經死亡。
}
```

這段程式碼會：

1. 建立一個敵人。
2. 讓它發射一次武器。
3. 進入一個回圈，模擬敵人被攻擊，每次扣 50 血。
4. 血量歸零後結束，觸發解構子，顯示敵人死亡訊息。

---

### 備註：

* 你可以為一個類別加上非常多的功能，像是計算傷害、防禦、移動動畫等等。
* 建構子可以定義很多個（重載），看你要怎麼初始化這個角色。
* 如果你用 `enemy robot();` 是宣告一個物件；
  如果用 `enemy@ robot = new enemy();`，是宣告一個參照（handle），兩者差異日後還會深入教。

---

### 建立物件與使用方法（物件的使用方式）

當你定義好一個類別（class）後，要使用它，就需要「建立物件」。這在程式裡通常叫做「實例化（instantiate）」，意思就是依照那個類別的樣子，產出一個真正可以使用的實體（物件）。

---

#### 使用類別的語法：

```bgt
enemy robot();
```

上面這行就是用來「建立」一個 `enemy` 類別的物件，叫做 `robot`。

接下來你就可以用 `robot` 這個物件，來操作它裡面的變數與方法，例如：

```bgt
robot.health = 50;         // 把血量改成 50
robot.move(1);             // 呼叫 move() 方法，讓敵人往某方向移動
robot.fire_weapon();       // 呼叫 fire_weapon() 方法，發射武器
```

---

#### 也可以給物件初始值：

如果你的類別有建構子（constructor），就能在建立物件時給它初始的血量、速度、位置等等。例如：

```bgt
enemy fast_enemy(100, 400, 0);  // 建立一個血量 100、速度 400 的敵人
```

這會使用你自定義的建構子：

```bgt
enemy(int init_health, int init_speed, int init_pos) {
  health = init_health;
  speed = init_speed;
  position = init_pos;
}
```

---

### 類別裡的解構子（destructor）

當一個物件不再使用（程式離開它的範圍），它的「解構子」會自動被呼叫。像這樣：

```bgt
~enemy() {
  alert("敵人", "敵人已被銷毀！");
}
```

只要這個敵人被刪除，或是程式結束，它就會跑這段程式碼，可以用來顯示訊息、釋放資源、停止聲音等等。

---

### 補充觀念（針對視障初學者）

* **類別 class** 就像是一個模型，像是「敵人的樣板」。
* **物件 object** 就像是用模型印出來的一隻一隻敵人。
* **建構子 constructor** 就是你做出這隻敵人時要幫它設定的基本資料。
* **方法 method** 就是你對這隻敵人下的指令，例如讓它移動、攻擊。
* **解構子 destructor** 就是這隻敵人要消失時會執行的指令，例如播放「死亡音效」。

---

### 應用 -  範例主題：簡單 RPG 背包 + 裝備系統

### 🎯 功能目標：

* 定義一個 `Item` 類別（代表道具）
* 定義一個 `Player` 類別（包含背包與裝備）
* 可以撿到物品放進背包
* 可以選擇使用或裝備某個物品
* 撿到重複物品會增加數量

---

```bgt
// 定義道具類別
class Item {
	string name;
	string type;  // 可為 "heal"（補血）、"weapon"（武器）、"armor"（防具）
	int value;    // 效果值，例如補血量、攻擊力、防禦力
	int count;    // 數量

	void use() {
		alert("使用物品", "你使用了 " + name);
		count--;
	}
}

// 定義玩家類別
class Player {
	string name;
	int hp = 100;
	int atk = 5;
	int def = 3;

	Item@[] inventory; // 背包（儲存所有道具）
	Item@ equipped_weapon = null;
	Item@ equipped_armor = null;

	// 加入道具進背包
	void pickup_item(string name, string type, int value) {
		for (int i = 0; i < inventory.length(); i++) {
			if (inventory[i].name == name) {
				inventory[i].count++;
				alert("撿到物品", "你撿到了一個 " + name + "，已擁有 " + inventory[i].count + " 個");
				return;
			}
		}
		// 新道具
		Item@ new_item = Item();
		new_item.name = name;
		new_item.type = type;
		new_item.value = value;
		new_item.count = 1;
		inventory.push_back(new_item);
		alert("撿到物品", "你獲得了新的物品：" + name);
	}

	// 顯示背包內容
	void show_inventory() {
		string info = "背包內容：\n";
		for (int i = 0; i < inventory.length(); i++) {
			info += inventory[i].name + " x" + inventory[i].count + "\n";
		}
		alert("背包", info);
	}

	// 裝備物品
	void equip_item(int index) {
		if (index < 0 || index >= inventory.length()) {
			alert("錯誤", "選項無效");
			return;
		}
		Item@ item = inventory[index];
		if (item.type == "weapon") {
			equipped_weapon = item;
			atk = 5 + item.value;
			alert("裝備武器", "你裝備了 " + item.name + "，攻擊力提升為 " + atk);
		} else if (item.type == "armor") {
			equipped_armor = item;
			def = 3 + item.value;
			alert("裝備防具", "你裝備了 " + item.name + "，防禦力提升為 " + def);
		} else {
			alert("不能裝備", item.name + " 不是可裝備的物品");
		}
	}

	// 使用道具
	void use_item(int index) {
		if (index < 0 || index >= inventory.length()) {
			alert("錯誤", "選項無效");
			return;
		}
		Item@ item = inventory[index];
		if (item.type == "heal") {
			hp += item.value;
			if (hp > 100) hp = 100;
			item.use();
			alert("回血", "你使用了 " + item.name + "，血量恢復至 " + hp);
		} else {
			alert("錯誤", item.name + " 不是補血物品");
		}
		// 使用完畢若數量為 0 則移除
		if (item.count <= 0) {
			inventory.removeAt(index);
		}
	}
}

void main() {
	Player me;
	me.name = "勇者";

	// 撿到一些道具
	me.pickup_item("小型治療藥水", "heal", 20);
	me.pickup_item("木劍", "weapon", 5);
	me.pickup_item("皮甲", "armor", 2);
	me.pickup_item("小型治療藥水", "heal", 20); // 測試堆疊道具

	me.show_inventory();

	// 選擇裝備武器（第 1 個物品是小型治療藥水，第 2 個才是武器）
	me.equip_item(1);

	// 使用治療藥水（第 0 個）
	me.use_item(0);

	me.show_inventory(); // 再次顯示背包內容
}
```

---

###  學習重點說明

| 概念           | 用法                                                 |
| ------------ | -------------------------------------------------- |
| 類別（class）    | 定義 `Item` 和 `Player`，讓每個物品與角色都有自己的屬性與方法            |
| 陣列           | 使用 `Item@[] inventory` 存放多個物品                      |
| 方法（function） | 透過 `pickup_item`、`equip_item`、`use_item` 操作角色與物品行為 |
| 判斷式          | 檢查裝備類型、背包數量等邏輯                                     |
| 物件操作         | 使用 `@物件` 來操作道具，如 `equipped_weapon = item`          |

---
## 11.進階物件技巧

上一章已經讓你學會了物件的基本用法，足夠讓你開始在製作遊戲時實際使用物件了。本章會進一步介紹更多物件導向的技巧，幫你提升程式設計的能力。不過要注意，這一章講的東西屬於比較**進階**的內容，所以你**第一次閱讀這份教學時，也可以先跳過這一章，之後再回來看**。

---

* **物件導向（object-oriented）** 是一種寫程式的方法，把一組資料（變數）和相關的功能（函式）包在一起，形成一個「物件」。這種方式非常適合用來做遊戲，像是「角色」、「怪物」、「武器」都可以變成物件。

* **進階技巧** 像是：怎麼讓物件更靈活使用、怎麼重複利用物件的功能、或讓多個物件互相合作。

* 如果你剛學完上一章的內容，建議可以先休息一下，等你真的需要用到更複雜的功能時再回來看這一章也沒關係。

---

### 11.1 什麼是物件？簡單回顧

在我們進入更進階的觀念之前，先快速複習一下你目前學過的「物件」概念。如果下面提到的東西你還不太熟，那可以回頭去看前一章，因為那是本章的基礎。

你可以把「物件」想成是一個**裝著資料與功能的盒子**。在這個盒子裡：

* 裝的是**變數**（這些叫做「屬性」property）
* 還有一些能做事情的**函式**（這些叫做「方法」method）

#### 🧠 舉個例子

假設我們有一個「音效」的物件，它的類別叫做 `sound`，那麼這個物件就會擁有「播放」這個方法，也就是 `.play()`。這是因為 `sound` 這個類別有定義「播放」這個功能。

---

#### 類別（class）是什麼？

每個物件都屬於某一種「類別」，這個類別就像是物件的藍圖。類別會決定這個物件：

* 會有哪些變數（屬性）
* 能做哪些事（方法）

所以說，你要讓一個角色能「移動」，那就要在 `player` 這個類別裡面定義 `move()` 方法。所有用這個類別建立出來的角色物件，就都可以移動了。

---

#### 物件的誕生與死亡：建構子與解構子

* 當你「建立」一個物件時，會自動執行一個叫做 **建構子（constructor）** 的函式。這個函式通常會幫物件做好初始化的工作，例如設定血量、速度等等。

* 當你「刪除」一個物件時，會自動執行一個叫做 **解構子（destructor）** 的函式，通常會處理善後、釋放記憶體之類的事。

✔️ 一個類別可以有「多個建構子」，也就是你可以根據不同的情況來建立不同樣子的物件（像是有的角色帶武器、有的沒有），但：

❌ 一個類別**只能有一個解構子**，因為物件被刪除的時候只能有一種善後方式。

---

#### ✅ 補充小筆記

* **建構子**在語法上就是和類別名稱一樣的函式，通常你在建立物件時它就會被自動呼叫。
* **解構子**在 BGT 裡是用波浪號 `~` 加上類別名稱來寫，例如：`~enemy()`

---

### 11.2 繼承（Inheritance）

想像一下，你正在做一款遊戲，裡面有主角會遇到各種不同的動物。我們先假設你已經寫好一個「鳥類（bird）」的類別，裡面定義了鳥會做的事情，例如走路、跑步、飛翔。像下面這樣：

```bgt
class bird
{
    void walk()
    {
        // 鳥走路的程式碼寫這裡
    }
    void run()
    {
        // 鳥跑步的程式碼寫這裡
    }
    void fly()
    {
        // 鳥飛行的程式碼寫這裡
    }
}
```

你可以建立幾隻鳥這樣用：

```bgt
void main()
{
    bird sparrow;
    bird dove;
    bird eagle;
    sparrow.run();
    dove.walk();
    eagle.fly(); // 飛向天空！🕊️
}
```

---

#### 現在我們想讓「麻雀」可以唱歌，怎麼辦？

你可能會想說，那我在 `bird` 裡面加個 `sing()` 方法就好了：

```bgt
void sing()
{
    // 唱歌的程式碼
}
```

但這樣一來，所有鳥類都會唱歌了。不對啊，鴿子應該「咕咕叫」，老鷹應該「哀鳴」，不應該每種鳥都能唱歌，這不真實啊！

---

#### 第二種做法：寫一個新的類別 `sparrow`

我們可以複製 `bird` 類別的所有東西，然後多加上 `sing()` 方法，變成一個 `sparrow` 類別：

```bgt
class sparrow
{
    void walk() { ... }
    void run() { ... }
    void fly() { ... }
    void sing() { ... }
}
```

這樣就能讓麻雀會唱歌，其他鳥不會。

但是這樣有三個大問題：

1. **重複太多**：`walk()`、`run()`、`fly()` 每個類別都要寫一次，很麻煩。
2. **不好維護**：如果你哪天發現 `fly()` 有 bug，要改四五個類別，很容易漏掉。
3. **類型不同無法混用**：如果你要做一個 `bird[] aviary(50);` 的鳥籠陣列，這個陣列只能放 `bird` 類型，不能放 `sparrow`，這樣也不好用。

---

#### 解決方式：使用「繼承（Inheritance）」

我們可以寫一個 `sparrow` 類別，它繼承 `bird` 類別的功能，然後只加上 `sing()` 方法就好：

```bgt
class sparrow : bird
{
    void sing()
    {
        // 麻雀唱歌的程式碼
    }
}
```

這樣寫，`sparrow` 這個類別就會自動擁有 `walk()`、`run()`、`fly()` 方法，不用再重寫一遍！

---

#### 實際使用範例

```bgt
void main()
{
    bird b1;
    bird b2;
    sparrow s;

    s.fly();    // 因為麻雀是鳥，所以可以飛
    s.sing();   // 麻雀有 sing() 方法

    bird@[] aviary = { b1, b2, s }; // 把麻雀也當作一隻鳥放進陣列裡
}
```

這裡的重點是：**`sparrow` 是 `bird` 的延伸類別，能當作 `bird` 使用**。

---

#### 小技巧：用「handle」來混用類型

```bgt
sparrow s;
bird@ b1 = s;  // 用 b1 這個 handle 來操作 s，但把它當成 bird

b1.fly();      // 可以，因為 fly() 是 bird 裡面的方法
s.sing();      // 可以，因為 s 是 sparrow
b1.sing();     // 不行，因為你現在是把它當成 bird，bird 沒有 sing()
```

最後這行：

```bgt
bird b2 = s;
```

這會「複製」一份新的 bird，不是參考而已。所以 `b2` 不會是麻雀，它只是根據麻雀的資料建立的一隻普通鳥。

---

#### 改寫方法（Override）

如果你想讓麻雀的 `fly()` 飛得跟其他鳥不一樣，你可以在 sparrow 類別中重新寫一次 `fly()` 方法：

```bgt
class sparrow : bird
{
    void sing() { ... }

    void fly()
    {
        // 麻雀專屬飛法
    }
}
```

這叫做 **override**（覆寫）：當子類別重新定義跟父類別同名的方法時，就會「覆蓋」掉原本的功能。

---

#### 多型（Polymorphism）：相同操作，對不同物件有不同表現

```bgt
bird@[] aviary = { b, s };
aviary[0].fly(); // 普通鳥的飛法
aviary[1].fly(); // 麻雀的飛法（因為覆寫過了）
```

這種「同一段程式碼，根據物件類型做不同事」的概念就叫 **多型**，是物件導向的核心之一。

---

#### 關於建構子與解構子

每當建立一個 `sparrow` 物件，其實也會先建立裡面「隱藏的」那個 `bird`。這就像蓋房子要先打地基。

```bgt
class bird
{
    double wingspan;
    bird(double wingspan)
    {
        this.wingspan = wingspan;
    }
}
```

在 `sparrow` 裡我們可以這樣呼叫 `bird` 的建構子：

```bgt
class sparrow : bird
{
    sparrow()
    {
        super(3); // 呼叫 bird 的建構子，給它 wingspan = 3
    }
}
```

這裡的 `super()` 就是呼叫「父類別的建構子」的意思。

---

#### 完整例子：多種鳥的實作

```bgt
class bird
{
    double wingspan;
    bird(double wingspan)
    {
        this.wingspan = wingspan;
    }

    void walk() { ... }
    void run() { ... }
    void fly() { ... }
    void make_sound() { ... }
}

class sparrow : bird
{
    sparrow() { super(3); }

    void sing()
    {
        alert("好美喔", "麻雀唱起了小旋律");
    }

    void make_sound() { sing(); }
}

class eagle : bird
{
    eagle() { super(20); }

    void cry()
    {
        alert("氣氛滿點", "老鷹哀鳴，迴盪在山谷");
    }

    void make_sound() { cry(); }
}

class dove : bird
{
    dove() { super(8); }

    void coo()
    {
        alert("有點怪", "鴿子咕咕地唱著只有鴿子懂的戀曲");
    }

    void make_sound() { coo(); }
}

void main()
{
    sparrow s;
    eagle e;
    dove d;

    bird@[] aviary = { s, e, d };

    for (uint i = 0; i < aviary.length(); i++)
    {
        aviary[i].fly();
        aviary[i].make_sound(); // 每種鳥都會發出自己的叫聲
    }
}
```

這就是完整展示「繼承、多型、建構子、覆寫」等物件導向技巧的範例！

---

#### 小提醒：繼承不是萬靈丹

繼承很強，但不要亂用。該用的時候再用，否則會讓類別關係過於複雜，維護變困難。

**何時該用繼承？**

* 有共同功能但又各自有差異的類別。
* 如果不用繼承，就要重複寫一堆一樣的程式碼。
* 模擬現實生活中「屬於某一類」的關係，例如：麻雀是鳥，鳥是動物。

---

### 🌟 題目：遊戲中的角色系統

我們要建立一個 RPG 遊戲角色系統：

* 所有角色都可以攻擊（attack）
* 不同角色攻擊方式不一樣
* 我們要能用一個角色陣列來操作各種角色（用到多型）
* 每個角色的攻擊都會顯示一個 alert 說明他怎麼攻擊

---

#### 🧱 類別架構設計

* `class character` → 基礎角色類別
* `class warrior : character` → 戰士，使用劍攻擊
* `class mage : character` → 法師，施放火球
* `class archer : character` → 弓箭手，射箭

---

#### 🧑‍💻 程式碼與註解

```bgt
// 基礎角色類別（父類別）
class character
{
    string name;

    // 建構子：設定角色名稱
    character(string name)
    {
        this.name = name;
    }

    // 基本攻擊方法：會被覆寫
    void attack()
    {
        alert("攻擊", name + " 攻擊了敵人！");
    }
}

// 戰士類別，繼承自 character
class warrior : character
{
    // 建構子，使用 super() 呼叫父類別的建構子
    warrior(string name) : character(name) {}

    // 覆寫 attack 方法：戰士用劍砍
    void attack()
    {
        alert("戰士攻擊", name + " 揮舞著大劍砍向敵人！");
    }
}

// 法師類別，繼承自 character
class mage : character
{
    mage(string name) : character(name) {}

    // 法師用火球攻擊
    void attack()
    {
        alert("法師攻擊", name + " 施放出火球術！");
    }
}

// 弓箭手類別，繼承自 character
class archer : character
{
    archer(string name) : character(name) {}

    // 弓箭手射箭攻擊
    void attack()
    {
        alert("弓箭手攻擊", name + " 射出一箭命中敵人！");
    }
}

// 主程式
void main()
{
    // 建立各種角色
    warrior w("阿勇");
    mage m("莉亞");
    archer a("小艾");

    // 多型關鍵：把不同子類別存成 character 類別的參考（handle）
    character@[] team = { w, m, a };

    // 統一呼叫 attack()，每個角色會表現不同
    for (uint i = 0; i < team.length(); i++)
    {
        team[i].attack();
    }
}
```

---

#### 🧠 解說重點

1. **繼承 inheritance**

   * `warrior`, `mage`, `archer` 都是 `character` 的子類別
   * 它們自動擁有 `character` 的屬性（如 name）與方法（如 attack）

2. **覆寫 override**

   * 每個子類別都自行寫一套 `attack()`，把父類別的方法蓋掉

3. **多型 polymorphism**

   * `character@[] team` 陣列裡存放不同角色物件
   * 呼叫 `team[i].attack()` 時，會根據真實物件類型執行對應的攻擊方式

4. **super()**

   * 每個子類別的建構子都用 `super(name)` 呼叫父類別的建構子，這樣 name 才能正確設定

---

####  延伸練習（你可以試著自己寫）

* 加一個 `healer` 類別，會幫隊友補血
* 每個角色都加一個 `int hp` 屬性，顯示血量
* 加一個 `status()` 方法顯示角色狀態

---
### 11.3 介面（Interfaces）

在上一節中，我們學會了一個強大的觀念叫「多型（polymorphism）」。其中一種實現多型的方式是透過「繼承」，因為在 BGT 中我們可以透過「父類別的 handle」來操作子類別的物件。

#### 🧠 什麼情況適合用繼承？

如果兩個類別有很多「重複的程式碼」或「概念上很像」，那就適合用繼承。例如：麻雀（sparrow）和鴿子（dove）這兩種鳥，牠們都會走路、會飛、會跑，這些功能可以寫在「bird」這個共通的父類別裡，避免重複寫程式。

---

#### 🧠 什麼情況 *不* 適合用繼承？

有時候，我們會遇到兩種完全不同的東西——它們：

* 程式碼完全不同
* 概念上也完全不一樣
* 但它們恰好「都做得到某件事」

這時候就不適合強迫用繼承了。

---

#### 🎵 範例：聲音來源（sound\_source）

我們來看一個例子：
鳥會叫。
樂器會發出聲音。

這兩種東西完全不同，但「牠們都會發出聲音」，這時候我們可以給它們一個共同的「介面」，叫 `sound_source`。

---

#### 🔑 什麼是介面（interface）？

介面就像是說：「只要你能做到這些事（例如 `make_sound()`），你就是一個 sound\_source。」

* 介面 **不是類別**
* 它 **不包含實作程式碼**
* 它只是「列出方法的名字和參數」（這叫方法的 signature）

---

#### 🧪 舉個例子

```bgt
interface sound_source
{
    void make_sound(); // 注意：只有名稱和參數，沒有內容
}
```

只要某個類別有 `make_sound()` 這個方法，它就算是「實作了這個介面」。

---

#### 🧩 實作介面的方法

跟繼承寫法一樣，用冒號 `:` 就可以：

```bgt
class bird : sound_source
```

```bgt
class musical_instrument : sound_source
```

---

#### 🐤 + 🎵 結合起來的完整範例

以下程式碼展示了：

* 繼承（例如 `sparrow` 是 `bird` 的子類別）
* 多型（用 bird@\[] 和 sound\_source@\[] 來操作不同物件）
* 介面（`sound_source` 讓我們可以把不同類別的東西放在一起）

```bgt
interface sound_source
{
    void make_sound();
}

class bird : sound_source
{
    double wingspan;
    bird(double wingspan)
    {
        this.wingspan = wingspan;
    }

    void walk() {}
    void run() {}
    void fly() {}

    void make_sound()
    {
        // 通用的鳥叫聲
    }
}

class sparrow : bird
{
    sparrow() : bird(3) {}

    void sing()
    {
        alert("好美", "麻雀唱了一段小旋律");
    }

    void make_sound()
    {
        sing(); // 呼叫自己的 sing 方法
    }
}

class eagle : bird
{
    eagle() : bird(20) {}

    void cry()
    {
        alert("有意境", "老鷹對著山頭發出悲鳴");
    }

    void make_sound()
    {
        cry();
    }
}

class dove : bird
{
    dove() : bird(8) {}

    void coo()
    {
        alert("很特別", "鴿子用只有牠們懂的語言唱情歌");
    }

    void make_sound()
    {
        coo();
    }
}

// 音樂類物件
class musical_instrument : sound_source
{
    uint complexity;
    musical_instrument(uint complexity)
    {
        this.complexity = complexity;
    }

    void make_sound()
    {
        alert("音樂", "你聽到音樂聲響起");
    }
}

class drum : musical_instrument
{
    drum() : musical_instrument(2) {}

    void make_sound()
    {
        alert("節奏", "你聽到穩定的鼓聲");
    }
}

void main()
{
    // 建立幾隻鳥，放進 bird 陣列
    sparrow s;
    eagle e;
    dove d;
    bird@[] aviary = { s, e, d };

    for (uint i = 0; i < aviary.length(); i++)
    {
        aviary[i].fly();
        aviary[i].make_sound();
    }

    // 建立鼓，加上鴿子、麻雀，一起放進 sound_source 陣列
    drum my_drum;
    sound_source@[] my_sound_sources = { d, s, my_drum };

    for (uint j = 0; j < my_sound_sources.length(); j++)
    {
        my_sound_sources[j].make_sound(); // 每個都會發出自己的聲音
    }
}
```

---

#### 📌 補充：介面可以多個實作

一個類別只能繼承一個父類別，但可以同時實作多個介面：

```bgt
class c : i1, i2, i3
{
    // 實作所有介面的方法
}
```

也可以一邊繼承、又一邊實作介面：

```bgt
class c1 : c2, i1, i2
{
    // 同時繼承 c2，也實作 i1 和 i2
}
```

```bgt
class 小明 : 人類, 會走路, 會講話
```

* 小明是「人類」（繼承）
* 同時他也具備「走路」和「講話」的功能（實作介面）

1. `:` 後面第一個是 **父類別**，只能有一個。
2. 後面接著列出的，是 **介面清單**，可以有很多個。
3. 實作介面就要「補齊」裡面的方法，不然會出錯。
4. 這是 BGT 語言允許「單一繼承 + 多重介面實作」的設計。



---

#### ✅ 小結重點整理

| 概念           | 說明                                        |
| ------------ | ----------------------------------------- |
| interface    | 列出方法名稱（沒有實作），讓類別來「承諾」要實作這些功能              |
| 實作 interface | 就是在類別裡提供對應的方法，與 signature 相同              |
| 多型           | 可以用 interface@\[] 來統一操作不同類別的物件，只要它們都實作了介面 |
| 不同於繼承        | 介面不代表類別之間有「階層關係」，只是功能上的「共通點」              |

---


### 11.4 運算子多載（Operator Overloading）

雖然這個段落的標題聽起來很嚴肅，但它其實比前面兩段講「繼承」和「介面」都還要容易懂。運算子多載，程式設計師喜歡稱它是「語法糖（syntactic sugar）」，意思就是它不是必需的，但用對的話可以讓程式碼變得更漂亮、更好懂，讀起來也更自然。不過你如果不想用，其實也可以完全不理它，沒關係。

---

#### 【觀念補充】什麼是「語法糖」？

這就像你泡一杯咖啡，咖啡本身就能喝，但加了糖會更好喝。語法糖也是這種意思——加上去比較舒服，但不加也不會壞掉。

---

我們現在來寫一個簡單的類別，用來表示「三維向量（3D vector）」。如果你忘了向量是什麼，我這邊幫你複習一下：

一個三維向量就是三個數字組成的。例如：`(3, 4, 5)` 就是一個三維向量。我們說這個向量有三個「分量」，也就是三個數字。通常，我們會用：

* x 分量表示水平（左右）
* y 分量表示前後
* z 分量表示上下

所以 `(3, 4, 5)` 這個向量的 y 值就是 4。

---


假設你站在一個固定地點（稱為原點），然後：

* 向右走 3 公尺（x = 3）
* 向前走 4 公尺（y = 4）
* 飛起來 5 公尺（z = 5）

這就是 `(3, 4, 5)` 的意思。

在遊戲裡面，向量經常被拿來描述：

* 東西在哪裡（位置）
* 動得多快（速度）
* 加速度是多少
* 朝哪個方向（朝向）

---

#### 三個向量常見的操作

我們來學幾種向量可以做的事情：

##### 1. **向量加法：**

把對應的 x、y、z 加起來。例如：

```
(3, 4, 5) + (5, 4, 3) = (8, 8, 8)
```

##### 2. **乘上常數（scalar）：**

把三個分量都乘上同一個數字。例如：

```
(3, 4, 5) * 6 = (18, 24, 30)
```

##### 3. **判斷兩個向量是否相等：**

只要 x、y、z 都一樣，就算是相等。例如：

```
(3, 4, 5) == (3, 4, 5) ✔️
(3, 4, 5) == (4, 5, 3) ❌
```

---

#### 我們用 BGT 來寫出這個向量類別

我會分兩次貼出程式碼：

1. **第一段：用傳統方法加法、乘法、比對**
2. **第二段：改成運算子多載（也就是讓你寫 v1 + v2 就能加）**

---

📌 **第一版本：用函式名稱來寫操作**

```bgt
class test_vector
{
    double x;
    double y;
    double z;

    // 建構函式，建立一個新的向量
    test_vector(double x, double y, double z)
    {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    // 回傳每個分量
    double get_x() { return x; }
    double get_y() { return y; }
    double get_z() { return z; }

    // 將向量轉成字串方便顯示
    string to_string()
    {
        return "(" + x + ", " + y + ", " + z + ")";
    }

    // 加上另一個向量
    test_vector add_to(test_vector@ other)
    {
        return test_vector(x + other.x, y + other.y, z + other.z);
    }

    // 乘上常數
    test_vector multiply_by_scalar(double scalar)
    {
        return test_vector(x * scalar, y * scalar, z * scalar);
    }

    // 判斷是否相等
    bool is_equal_to(test_vector@ other)
    {
        return x == other.x && y == other.y && z == other.z;
    }
}
```

---

📌 **使用方式：**

```bgt
void main()
{
    test_vector v1(3, 4, 5);
    test_vector v2(5, 4, 3);
    test_vector@ v3 = v1.add_to(v2); // 比較難讀

    alert("加法", v1.to_string() + " + " + v2.to_string() + " = " + v3.to_string());

    test_vector@ v4 = v1.multiply_by_scalar(6);
    alert("乘法", "6 * " + v1.to_string() + " = " + v4.to_string());

    if(v1.is_equal_to(v2))
        alert("結果", "兩個向量相等");
    else
        alert("結果", "兩個向量不相等");
}
```

---

你有沒有覺得 `v1.add_to(v2)` 這樣寫起來很笨拙？
如果能像數學一樣寫成 `v1 + v2`，不是更直覺嗎？

這就是「運算子多載」的用途。

---

#### 📌 運算子多載版本的向量類別（Operator Overloading）

你會看到我們把：

* `add_to(v2)` 改成 `v1 + v2`
* `multiply_by_scalar(6)` 改成 `v1 * 6`
* `is_equal_to(v2)` 改成 `v1 == v2`

這樣寫起來是不是跟數學公式一樣簡單又清楚？

---

#### ✅ 完整程式碼：支援 +、\*、== 的 test\_vector 類別

```bgt
class test_vector
{
    double x;
    double y;
    double z;

    // 建構子：建立向量
    test_vector(double x, double y, double z)
    {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    // 將向量轉成字串格式
    string to_string()
    {
        return "(" + x + ", " + y + ", " + z + ")";
    }

    // 多載加法運算子（v1 + v2）
    test_vector opAdd(test_vector other)
    {
        return test_vector(x + other.x, y + other.y, z + other.z);
    }

    // 多載乘法運算子（v1 * 數字）
    test_vector opMul(double scalar)
    {
        return test_vector(x * scalar, y * scalar, z * scalar);
    }

    // 多載相等運算子（v1 == v2）
    bool opEquals(test_vector other)
    {
        return x == other.x && y == other.y && z == other.z;
    }
}
```

---

#### ✅ 使用方式（main 函式）

```bgt
void main()
{
    test_vector v1(3, 4, 5);
    test_vector v2(5, 4, 3);

    // 使用加法運算子
    test_vector v3 = v1 + v2;
    alert("加法", v1.to_string() + " + " + v2.to_string() + " = " + v3.to_string());

    // 使用乘法運算子
    test_vector v4 = v1 * 6;
    alert("乘法", "6 * " + v1.to_string() + " = " + v4.to_string());

    // 使用相等運算子
    if(v1 == v2)
        alert("比對", "向量 v1 和 v2 相等");
    else
        alert("比對", "向量 v1 和 v2 不相等");
}
```

---

#### 🧠 重點整理

| 動作   | 原本方法名稱                  | 改成運算子      | 多載的函式名稱    |
| ---- | ----------------------- | ---------- | ---------- |
| 加法   | `add_to(v)`             | `v1 + v2`  | `opAdd`    |
| 乘上常數 | `multiply_by_scalar(n)` | `v1 * n`   | `opMul`    |
| 相等比對 | `is_equal_to(v)`        | `v1 == v2` | `opEquals` |

---

#### 📌 小提醒：

* **函式名稱要固定寫法：**
  `opAdd`, `opMul`, `opEquals` 這些名字是 BGT 規定的，要照用。
* **不能亂命名：** 如果你寫成 `opPlus` 或 `addOperator` 是不會動的。
* **程式可讀性大提升！**

---
###  12. 函式的 Handle（函式的參考）

你在前面兩章已經學過了，「handle」是一種傳遞資料的方式，不會建立副本，而是像地址一樣指向原本的資料。簡單來說，它就像「地址紙條」，你給我地址我自己去找那個東西，而不是直接把東西拿來給我。

這個概念也可以套用到「函式」上 —— 也就是說，我們也可以把「函式的 handle」傳來傳去！

這要分兩個步驟來做：

---

#### ✅ 第一步：定義一種「函式型別」（function type）

我們要先告訴編譯器：「我接下來要傳來傳去的這種函式，它的樣子是什麼？」這個「樣子」指的是函式的參數跟回傳值，也就是俗稱的 **signature（簽章）**。

舉例來說，下面這行的意思是「定義一種不回傳東西、也不需要參數的函式型別」：

```bgt
funcdef void my_function_type();
```

這行就像是在說：「我現在創造一種函式型別，它名字叫 `my_function_type`，而這種函式不收參數，也不回傳值。」

---

#### ✅ 第二步：使用函式 handle 就像使用其他變數一樣

你可以像下面這樣，把這種函式當作變數用，然後用 `@` 來代表它是一個「handle」（也就是指標、參考）。

來看一個範例：

```bgt
funcdef void my_function_type();

void do_n_times(my_function_type@ what, uint n)
{
    for(uint i = 0; i < n; i++)
    {
        what(); // 呼叫函式
    }
}

void print_a_message()
{
    alert("Message", "The answer is 42.");
}

void main()
{
    do_n_times(print_a_message, 3);
}
```

---

#### 💡 補充說明

這段程式碼的重點在於 `do_n_times` 這個函式：

* 它接收一個函式的 handle（也就是 `what`），
* 還有一個數字 `n`，
* 然後它就會重複執行這個函式 `n` 次。

在主程式中，`do_n_times(print_a_message, 3);` 的意思是：「把 `print_a_message` 這個函式當作參數傳進去，重複執行 3 次。」

---

#### 🎯 這有什麼用？

有時候你寫的程式不知道會執行哪個函式，或者你希望未來讓使用者決定要執行哪個函式，那你就可以用這種方式，把函式的 handle 傳進去，而不是「寫死」要執行哪個函式。

就像你做一款遊戲，想要做一個「選單選項」，每個選項可能執行不同的功能，你可以用函式 handle 來處理，這樣選項就有彈性了！

---

###  13. 使用多個腳本檔（Script）

BGT 有一個超級實用的功能，就是可以把很多程式分成不同的檔案寫，然後組合起來變成一個完整的遊戲。

為什麼這樣做？

因為當你的遊戲越來越大時，把所有程式碼都寫在同一個檔案會變得超級難找又混亂。例如你要找「玩家的攻擊邏輯」，卻還要捲過 1500 行的主程式，根本是災難！

---

#### ✅ 怎麼分成多個檔案？

你只要在主程式中加上這樣一行：

```bgt
#include "scriptname.bgt"
```

這會告訴 BGT：「去讀取這個叫 `scriptname.bgt` 的檔案，當作是主程式的一部分。」

包含進來的檔案就像是「貼進來」一樣，裡面的變數、函式、類別你都可以直接用。

---

#### ✅ 要注意的幾個重點：

1. **只有主程式能有 `main()` 函式**
   其他被 include 的檔案 *不能有 main() 函式*，不然編譯時會出錯，因為會出現「重複定義」的情況。

2. **讀取順序**
   BGT 會先從目前的工作資料夾找這個檔案，如果找不到，才會去內建的 include 資料夾找。找不到就會報錯。

3. **玩家不需要 include 的檔案**
   因為這些檔案會在編譯時全部打包進最終的程式中，使用者不需要額外帶著這些檔案。

---

#### 🧩 常見的腳本拆分方式

你可以依功能分檔，例如：

* `menu.bgt`：放選單的功能
* `player.bgt`：放玩家的控制邏輯
* `ai.bgt`：放電腦的行為邏輯
* `sound.bgt`：放音效的處理方式

這樣你的主程式可能只有 200 行，其他東西都收納得乾乾淨淨，超好維護！

---

### 📘 最後的叮嚀

好啦，差不多就這些了！
如果你能一路學到這邊，那表示你已經具備寫 BGT 遊戲所需的基本能力。

接下來，我會 **強烈建議你做幾件事**：

---

#### ✅ 回頭複習

花點時間把你學過的內容重新想一想，尤其是那些你覺得「還不太懂」的章節或觀念，可以回去多讀幾遍。

* 再讀一次那些程式碼範例
* 自己動手試著修改看看
* 嘗試改出你自己的版本

這樣你會更有感覺！

---

#### ✅ 多多練習、勇敢試做

這份教學裡的範例程式碼都可以拿來玩看看，把它們改一改、拼一拼，看能不能變成你自己的小作品。

**玩程式就像玩積木一樣**，多試、多失敗，才能更快上手。

---

#### ✅ 用得到的工具還有幫助檔

別忘了，BGT 附的說明檔裡還有完整的函式與物件說明（也就是參考手冊）——

裡面不但有介紹每個指令怎麼用，還會附上「可正常運作」的範例程式。

你在寫遊戲時如果卡關，記得打開這些檔案查一下，很可能馬上就能找到解答！

---

### 🧡 給你的祝福

到這裡我能說的就差不多了，只能祝你一切順利，**快樂寫遊戲！**

希望不久之後，大家就能玩到你的第一款熱門遊戲！🔥

---
